From a42f41c601df19bae524bca795ee9f0f5b4e7097 Mon Sep 17 00:00:00 2001 From: Alireza Assadzadeh Date: Fri, 22 May 2020 11:07:28 -0400 Subject: [PATCH] Update to version v0.8.1-beta --- .github/ISSUE_TEMPLATE/bug_report.md | 49 + .github/ISSUE_TEMPLATE/feature_request.md | 45 + .github/PULL_REQUEST_TEMPLATE.md | 5 + CHANGELOG.md | 7 + LICENSE.txt | 175 ++ NOTICE => NOTICE.txt | 4 + deployment/build-patterns.sh | 31 + source/lerna.json | 2 +- source/package.json | 18 +- .../aws-apigateway-dynamodb/README.md | 2 +- .../aws-apigateway-dynamodb/lib/index.ts | 6 +- .../aws-apigateway-dynamodb/package.json | 26 +- .../apigateway-dynamodb.test.js.snap | 6 +- ...teg.apigateway-dynamodb-CRUD.expected.json | 16 +- .../test/integ.no-arguments.expected.json | 16 +- .../aws-apigateway-lambda/lib/index.ts | 24 +- .../aws-apigateway-lambda/package.json | 26 +- .../test.apigateway-lambda.test.js.snap | 1765 ++++++++++++++--- .../test/integ.deployFunction.expected.json | 148 +- .../test/integ.existingFunction.expected.json | 90 +- .../test/test.apigateway-lambda.test.ts | 30 + .../aws-apigateway-sqs/lib/index.ts | 6 +- .../aws-apigateway-sqs/package.json | 30 +- .../__snapshots__/apigateway-sqs.test.js.snap | 118 +- .../integ.apigateway-sqs-crud.expected.json | 232 +-- .../test/integ.no-arguments.expected.json | 224 +-- .../README.md | 3 +- .../lib/index.ts | 20 +- .../package.json | 34 +- ....cloudfront-apigateway-lambda.test.js.snap | 513 +++-- .../test/integ.no-arguments.expected.json | 437 ++-- .../test.cloudfront-apigateway-lambda.test.ts | 4 +- .../aws-cloudfront-apigateway/README.md | 4 +- .../aws-cloudfront-apigateway/lib/index.ts | 17 +- .../aws-cloudfront-apigateway/package.json | 30 +- .../test.cloudfront-apigateway.test.js.snap | 347 ++-- .../test/integ.no-arguments.expected.json | 201 +- .../test/test.cloudfront-apigateway.test.ts | 4 +- .../aws-cloudfront-s3/README.md | 5 +- .../aws-cloudfront-s3/lib/index.ts | 16 +- .../aws-cloudfront-s3/package.json | 22 +- .../test.cloudfront-s3.test.js.snap | 113 ++ .../test/integ.no-arguments.expected.json | 129 +- .../integ.no-security-headers.expected.json | 296 +++ .../test/integ.no-security-headers.ts | 32 + .../test/test.cloudfront-s3.test.ts | 93 + .../aws-cognito-apigateway-lambda/README.md | 8 +- .../lib/index.ts | 18 +- .../package.json | 26 +- ...est.cognito-apigateway-lambda.test.js.snap | 367 ++-- .../test/integ.no-arguments.expected.json | 225 ++- .../test.cognito-apigateway-lambda.test.ts | 29 +- .../README.md | 14 +- .../lib/index.ts | 18 +- .../package.json | 46 +- ...m-lambda-elasticsearch-kibana.test.js.snap | 571 +++--- ...stream-lambda-elasticsearch-kibana.test.ts | 2 +- .../test/integ.no-arguments.expected.json | 221 ++- .../aws-dynamodb-stream-lambda/README.md | 4 +- .../aws-dynamodb-stream-lambda/lib/index.ts | 6 +- .../aws-dynamodb-stream-lambda/package.json | 26 +- .../dynamodb-stream-lambda.test.js.snap | 72 +- .../test/dynamodb-stream-lambda.test.ts | 8 +- .../test/integ.no-arguments.expected.json | 72 +- .../aws-events-rule-lambda/README.md | 4 +- .../aws-events-rule-lambda/lib/index.ts | 6 +- .../aws-events-rule-lambda/package.json | 26 +- .../events-rule-lambda.test.js.snap | 48 +- .../test/events-rule-lambda.test.ts | 6 +- ...nteg.events-rule-no-argument.expected.json | 48 +- .../aws-iot-kinesisfirehose-s3/README.md | 6 +- .../aws-iot-kinesisfirehose-s3/lib/index.ts | 6 +- .../aws-iot-kinesisfirehose-s3/package.json | 34 +- .../aws-iot-lambda-dynamodb/README.md | 6 +- .../aws-iot-lambda-dynamodb/lib/index.ts | 6 +- .../aws-iot-lambda-dynamodb/package.json | 34 +- .../iot-lambda-dynamodb.test.js.snap | 22 +- .../integ.iot-lambda-dynamodb.expected.json | 64 +- .../test/iot-lambda-dynamodb.test.ts | 6 +- .../aws-iot-lambda/README.md | 4 +- .../aws-iot-lambda/lib/index.ts | 6 +- .../aws-iot-lambda/package.json | 26 +- .../__snapshots__/iot-lambda.test.js.snap | 56 +- .../integ.iot-lambda-new-func.expected.json | 56 +- .../aws-iot-lambda/test/iot-lambda.test.ts | 6 +- .../package.json | 38 +- .../aws-kinesisfirehose-s3/README.md | 4 +- .../aws-kinesisfirehose-s3/lib/index.ts | 4 +- .../aws-kinesisfirehose-s3/package.json | 30 +- .../aws-kinesisstreams-lambda/lib/index.ts | 12 +- .../aws-kinesisstreams-lambda/package.json | 30 +- .../test.kinesisstreams-lambda.test.js.snap | 132 +- .../test/integ.deployFunction.expected.json | 130 +- .../test/test.kinesisstreams-lambda.test.ts | 10 +- .../aws-lambda-dynamodb/README.md | 4 +- .../aws-lambda-dynamodb/lib/index.ts | 19 +- .../aws-lambda-dynamodb/package.json | 22 +- .../lambda-dynamodb.test.js.snap | 62 +- .../integ.add-secondary-index.expected.json | 98 +- .../test/integ.no-arguments.expected.json | 62 +- .../test/integ.set-billing-mode.expected.json | 28 +- .../test/lambda-dynamodb.test.ts | 4 +- .../aws-lambda-elasticsearch-kibana/README.md | 12 +- .../lib/index.ts | 26 +- .../package.json | 34 +- .../lambda-elasticsearch-kibana.test.js.snap | 151 +- .../test/integ.no-arguments.expected.json | 151 +- .../test/lambda-elasticsearch-kibana.test.ts | 2 +- .../aws-lambda-s3/lib/index.ts | 2 +- .../aws-lambda-s3/package.json | 22 +- .../test/__snapshots__/lambda-s3.test.js.snap | 128 +- .../test/integ.deployFunction.expected.json | 176 +- .../aws-lambda-sns/lib/index.ts | 2 +- .../aws-lambda-sns/package.json | 26 +- .../__snapshots__/lambda-sns.test.js.snap | 276 +-- .../test/integ.deployFunction.expected.json | 136 +- .../aws-s3-lambda/lib/index.ts | 14 +- .../aws-s3-lambda/package.json | 34 +- .../test/__snapshots__/s3-lambda.test.js.snap | 50 +- .../integ.existing-s3-bucket.expected.json | 18 +- .../test/integ.existing-s3-bucket.ts | 2 +- .../test/integ.no-arguments.expected.json | 30 +- .../aws-s3-lambda/test/integ.no-arguments.ts | 2 +- .../aws-sns-lambda/lib/index.ts | 2 +- .../aws-sns-lambda/package.json | 34 +- .../__snapshots__/sns-lambda.test.js.snap | 120 +- .../test/integ.no-arguments.expected.json | 136 +- .../aws-sqs-lambda/README.md | 8 +- .../aws-sqs-lambda/lib/index.ts | 18 +- .../aws-sqs-lambda/package.json | 30 +- .../test.sqs-lambda.test.js.snap | 256 +-- .../test/integ.deployFunction.expected.json | 40 +- .../test/integ.existingFunction.expected.json | 20 +- .../test/test.sqs-lambda.test.ts | 6 +- .../core/lib/apigateway-defaults.ts | 89 +- .../core/lib/apigateway-helper.ts | 120 +- .../lib/cloudfront-distribution-defaults.ts | 74 +- .../lib/cloudfront-distribution-helper.ts | 184 +- .../core/lib/cognito-helper.ts | 16 + .../core/lib/kinesis-streams-helper.ts | 2 +- .../core/lib/kms-helper.ts | 2 +- .../core/lib/lambda-helper.ts | 12 +- .../core/lib/override-warning-service.ts | 86 + .../core/lib/sqs-defaults.ts | 5 +- .../core/lib/sqs-helper.ts | 5 +- .../@aws-solutions-konstruk/core/lib/utils.ts | 31 +- .../@aws-solutions-konstruk/core/package.json | 98 +- .../apigateway-helper.test.js.snap | 246 +-- ...stribution-api-gateway-helper.test.js.snap | 117 +- ...dfront-distribution-s3-helper.test.js.snap | 113 ++ .../congnito-helper.test.js.snap | 138 +- .../elasticsearch-helper.test.js.snap | 69 +- .../core/test/apigateway-helper.test.ts | 128 +- .../cloudfront-distribution-s3-helper.test.ts | 258 +++ .../core/test/congnito-helper.test.ts | 3 +- .../test/kinesis-streams-defaults.test.ts | 4 +- .../core/test/lambda-event-source.test.ts | 28 + .../test/override-warning-service.test.ts | 206 ++ source/tools/cdk-integ-tools/.gitignore | 10 + source/tools/cdk-integ-tools/.npmignore | 9 + .../tools/cdk-integ-tools/LICENSE | 28 +- source/tools/cdk-integ-tools/NOTICE | 2 + source/tools/cdk-integ-tools/README.md | 61 + source/tools/cdk-integ-tools/bin/cdk-integ | 2 + .../cdk-integ-tools/bin/cdk-integ-assert | 2 + .../cdk-integ-tools/bin/cdk-integ-assert.ts | 51 + source/tools/cdk-integ-tools/bin/cdk-integ.ts | 72 + .../cdk-integ-tools/lib/integ-helpers.ts | 257 +++ source/tools/cdk-integ-tools/package.json | 48 + source/tools/cdk-integ-tools/tsconfig.json | 20 + .../aws-s3-static-website/package.json | 22 +- .../s3-static-site-stack.test.js.snap | 131 +- .../test/integ.basic-deployment.expected.json | 147 +- .../test/integ.basic-deployment.ts | 2 +- .../aws-serverless-image-handler/package.json | 40 +- ...test.serverless-image-handler.test.js.snap | 705 ++++--- .../test/integ.basic-deployment.expected.json | 573 +++--- .../lib/serverless-backend-stack.ts | 3 +- .../aws-serverless-web-app/package.json | 32 +- .../s3-static-site-stack.test.js.snap | 131 +- .../serverless-backend-stack.test.js.snap | 738 +++---- ...3-static-website-deployment.expected.json} | 147 +- ...integ.001-s3-static-website-deployment.ts} | 0 ...nteg.002-backend-deployment.expected.json} | 302 +-- ...ent.ts => integ.002-backend-deployment.ts} | 0 .../test/serverless-backend-stack.test.ts | 4 +- 186 files changed, 10730 insertions(+), 5126 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 LICENSE.txt rename NOTICE => NOTICE.txt (92%) create mode 100755 deployment/build-patterns.sh create mode 100644 source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.expected.json create mode 100644 source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.ts create mode 100644 source/patterns/@aws-solutions-konstruk/core/lib/override-warning-service.ts create mode 100644 source/patterns/@aws-solutions-konstruk/core/test/override-warning-service.test.ts create mode 100644 source/tools/cdk-integ-tools/.gitignore create mode 100644 source/tools/cdk-integ-tools/.npmignore rename LICENSE => source/tools/cdk-integ-tools/LICENSE (89%) create mode 100644 source/tools/cdk-integ-tools/NOTICE create mode 100644 source/tools/cdk-integ-tools/README.md create mode 100755 source/tools/cdk-integ-tools/bin/cdk-integ create mode 100755 source/tools/cdk-integ-tools/bin/cdk-integ-assert create mode 100644 source/tools/cdk-integ-tools/bin/cdk-integ-assert.ts create mode 100644 source/tools/cdk-integ-tools/bin/cdk-integ.ts create mode 100644 source/tools/cdk-integ-tools/lib/integ-helpers.ts create mode 100644 source/tools/cdk-integ-tools/package.json create mode 100644 source/tools/cdk-integ-tools/tsconfig.json rename source/use_cases/aws-serverless-web-app/test/{integ.s3-static-website-deployment.expected.json => integ.001-s3-static-website-deployment.expected.json} (74%) rename source/use_cases/aws-serverless-web-app/test/{integ.s3-static-website-deployment.ts => integ.001-s3-static-website-deployment.ts} (100%) rename source/use_cases/aws-serverless-web-app/test/{integ.backend-deployment.expected.json => integ.002-backend-deployment.expected.json} (73%) rename source/use_cases/aws-serverless-web-app/test/{integ.backend-deployment.ts => integ.002-backend-deployment.ts} (100%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..3634b9aab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,49 @@ +--- +name: "\U0001F41B Bug Report" +about: Report a bug +labels: bug, needs-triage +--- + + + + + + +### Reproduction Steps + + + + + + +### Error Log + + + + + + +### Environment + + - **CDK CLI Version :** + - **CDK Framework Version:** + - **Konstruk Version :** + - **OS :** + - **Language :** + +### Other + + + + + + +--- + +This is :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..c2812d3e6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,45 @@ +--- +name: "\U0001F680 Feature Request" +about: Request a new feature +labels: feature-request, needs-triage +--- + + + + + + + +### Use Case + + + + + + + +### Proposed Solution + + + + + + + +### Other + + + + + + + +* [ ] :wave: I may be able to implement this feature request +* [ ] :warning: This feature might incur a breaking change + +--- + +This is a :rocket: Feature Request diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..283f6872b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ +*Issue #, if available:* + +*Description of changes:* + +By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e42524d5..f65f0ded8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.1-beta] - 2020-05-21 +### Changed +- Upgraded to CDK v1.40.0 +- Ability to emit a warning to the console when a prescriptive default value is overridden by the user +- Automatic injection of best practice HTTP security headers in all HTTP responses from cloudfront +- Fix the Cfn Nag warning Cloudfront should use minimum protocol version TLS 1.2 (W70) + ## [0.8.0-beta] - 2020-03-31 ### Added - Initial public beta release diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..19dc35b24 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. \ No newline at end of file diff --git a/NOTICE b/NOTICE.txt similarity index 92% rename from NOTICE rename to NOTICE.txt index 135629617..833fe2b9f 100644 --- a/NOTICE +++ b/NOTICE.txt @@ -11,8 +11,10 @@ THIRD PARTY COMPONENTS ********************** This software includes third party software subject to the following copyrights: +@types/deep-diff under the Massachusetts Institute of Technology (MIT) license @types/jest under the Massachusetts Institute of Technology (MIT) license @types/node under the Massachusetts Institute of Technology (MIT) license +@types/npmlog under the Massachusetts Institute of Technology (MIT) license @typescript-eslint/eslint-plugin under the Massachusetts Institute of Technology (MIT) license @typescript-eslint/parser under the BSD-2-Clause license aws-cdk under the Apache License Version 2.0 @@ -23,6 +25,7 @@ chai under the Massachusetts Institute of Technology (MIT) license color under the Massachusetts Institute of Technology (MIT) license color-name under the Massachusetts Institute of Technology (MIT) license deepmerge under the MIT License +deep-diff under the MIT License eslint under the Massachusetts Institute of Technology (MIT) license eslint-import-resolver-node under the Massachusetts Institute of Technology (MIT) license eslint-import-resolver-typescript under the ISC license @@ -36,6 +39,7 @@ lerna under the Massachusetts Institute of Technology (MIT) license minimist under the Massachusetts Institute of Technology (MIT) license mocha under the Massachusetts Institute of Technology (MIT) license moment under the Massachusetts Institute of Technology (MIT) license +npmlog under the ISC license npm-run-all under the Massachusetts Institute of Technology (MIT) license nyc under the ISC license sharp under the Apache License Version 2.0 diff --git a/deployment/build-patterns.sh b/deployment/build-patterns.sh new file mode 100755 index 000000000..60008d7ac --- /dev/null +++ b/deployment/build-patterns.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -euo pipefail + +deployment_dir="$PWD" +source_dir="$deployment_dir/../source" + +echo "=============================================================================================" +echo "building cdk-integ-tools..." +cd $source_dir/tools/cdk-integ-tools +npm install +npm run build +npm link + +bail="--bail" +runtarget="build+lint+test" +cd $source_dir/ + +export PATH=$(npm bin):$PATH +export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" + +echo "=============================================================================================" +echo "installing..." +yarn install --frozen-lockfile + +echo "=============================================================================================" +echo "building..." +time lerna run $bail --stream $runtarget || fail + +echo "=============================================================================================" +echo "packaging..." +time lerna run $bail --stream jsii-pacmak || fail diff --git a/source/lerna.json b/source/lerna.json index 80d43a175..cb6781ba1 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -7,5 +7,5 @@ "./use_cases/*" ], "rejectCycles": "true", - "version": "0.8.0" + "version": "0.8.1" } diff --git a/source/package.json b/source/package.json index 8523bf35e..e709e1248 100644 --- a/source/package.json +++ b/source/package.json @@ -1,6 +1,6 @@ { "name": "aws-solutions-konstruk", - "version": "0.8.0", + "version": "0.8.1", "description": "AWS Solutions Konstruk Library", "repository": { "type": "git", @@ -23,10 +23,10 @@ "eslint-plugin-license-header": "^0.2.0", "fs-extra": "^8.1.0", "jest": "^24.9.0", - "jsii": "~0.22.0", - "jsii-pacmak": "~0.22.0", + "jsii": "^1.4.1", + "jsii-pacmak": "^1.4.1", "tslint": "^5.20.1", - "typescript": "~3.8.2" + "typescript": "~3.8.3" }, "devDependencies": { "lerna": "^3.18.4" @@ -38,7 +38,15 @@ ], "nohoist": [ "**/deepmerge", - "**/deepmerge/**" + "**/deepmerge/**", + "**/npmlog", + "**/npmlog/**", + "**/@types/npmlog", + "**/@types/npmlog/**", + "**/deep-diff", + "**/deep-diff/**", + "**/@types/deep-diff", + "**/@types/deep-diff/**" ] } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/README.md b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/README.md index ce68175ce..b551ac27b 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/README.md @@ -68,7 +68,7 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| |restApi()|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|Returns an instance of the api.RestApi created by the construct.| -|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Retruns an instance of dynamodb.Table created by the construct.| +|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Returns an instance of dynamodb.Table created by the construct.| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/lib/index.ts index 78fa5984c..b4a72ae80 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/lib/index.ts @@ -19,7 +19,7 @@ import * as dynamodb from '@aws-cdk/aws-dynamodb'; import { overrideProps } from '@aws-solutions-konstruk/core'; /** - * @summary The properties for the ApiGatewayToSqs class. + * @summary The properties for the ApiGatewayToDynamoDB class. */ export interface ApiGatewayToDynamoDBProps { /** @@ -87,7 +87,7 @@ export class ApiGatewayToDynamoDB extends Construct { private apiGateway: api.RestApi; /** - * @summary Constructs a new instance of the ApiGatewayToSqs class. + * @summary Constructs a new instance of the ApiGatewayToDynamoDB class. * @param {cdk.App} scope - represents the scope for all the resources. * @param {string} id - this is a a scope-unique id. * @param {CloudFrontToApiGatewayToLambdaProps} props - user provided props for the construct. @@ -215,7 +215,7 @@ export class ApiGatewayToDynamoDB extends Construct { } /** - * @summary Retruns an instance of dynamodb.Table created by the construct. + * @summary Returns an instance of dynamodb.Table created by the construct. * @returns {dynamodb.Table} Instance of dynamodb.Table created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/package.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/package.json index 7a1f6de41..fd384e38d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-apigateway-dynamodb", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS API Gateway and Amazon DynamoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/__snapshots__/apigateway-dynamodb.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/__snapshots__/apigateway-dynamodb.test.js.snap index 9cde02214..b05ca3164 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/__snapshots__/apigateway-dynamodb.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/__snapshots__/apigateway-dynamodb.test.js.snap @@ -139,7 +139,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F377bb1a1fb193e128da423ded28aa899d": Object { + "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F3c3e5f83088fae14392dcefa7a52bda00": Object { "DependsOn": Array [ "testapigatewaydynamodbdefaultRestApiidGET94B6F433", "testapigatewaydynamodbdefaultRestApiidFD6A9E91", @@ -171,10 +171,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F377bb1a1fb193e128da423ded28aa899d", + "Ref": "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F3c3e5f83088fae14392dcefa7a52bda00", }, "MethodSettings": Array [ Object { diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.expected.json index ac65b24ea..76eeec074 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.expected.json @@ -24,6 +24,11 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, + "testapigatewaydynamodbApiAccessLogGroup3F457756": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, "testapigatewaydynamodbRestApi80489300": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -35,7 +40,7 @@ "Name": "RestApi" } }, - "testapigatewaydynamodbRestApiDeployment1898674B2ca5fe4ea0afc42b42d1b0c68ddb65ce": { + "testapigatewaydynamodbRestApiDeployment1898674Bf06c85f4d2c4a0739d5158ea0dd6288a": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -74,10 +79,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testapigatewaydynamodbRestApiDeployment1898674B2ca5fe4ea0afc42b42d1b0c68ddb65ce" + "Ref": "testapigatewaydynamodbRestApiDeployment1898674Bf06c85f4d2c4a0739d5158ea0dd6288a" }, "MethodSettings": [ { @@ -456,11 +461,6 @@ ] } }, - "testapigatewaydynamodbApiAccessLogGroup3F457756": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testapigatewaydynamodbLambdaRestApiCloudWatchRoleD176CA9E": { "Type": "AWS::IAM::Role", "Properties": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.no-arguments.expected.json index 258a1c11d..d1706f59f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-dynamodb/test/integ.no-arguments.expected.json @@ -24,6 +24,11 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, + "testapigatewaydynamodbdefaultApiAccessLogGroup0192183A": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, "testapigatewaydynamodbdefaultRestApi9102FDF9": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -35,7 +40,7 @@ "Name": "RestApi" } }, - "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F377bb1a1fb193e128da423ded28aa899d": { + "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F3c3e5f83088fae14392dcefa7a52bda00": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -71,10 +76,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F377bb1a1fb193e128da423ded28aa899d" + "Ref": "testapigatewaydynamodbdefaultRestApiDeploymentFAC726F3c3e5f83088fae14392dcefa7a52bda00" }, "MethodSettings": [ { @@ -201,11 +206,6 @@ ] } }, - "testapigatewaydynamodbdefaultApiAccessLogGroup0192183A": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testapigatewaydynamodbdefaultLambdaRestApiCloudWatchRoleEF1FBFD7": { "Type": "AWS::IAM::Role", "Properties": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/lib/index.ts index 34b852ae3..a461340b6 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/lib/index.ts @@ -16,7 +16,6 @@ import * as api from '@aws-cdk/aws-apigateway'; import * as lambda from '@aws-cdk/aws-lambda'; import * as defaults from '@aws-solutions-konstruk/core'; import { Construct } from '@aws-cdk/core'; -import { LogGroup } from '@aws-cdk/aws-logs'; /** * The properties for the ApiGatewayToLambda class. @@ -71,33 +70,14 @@ export class ApiGatewayToLambda extends Construct { super(scope, id); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps }); // Setup the API Gateway - this.api = defaults.GlobalLambdaRestApi(scope, this.fn, props.apiGatewayProps); - - // Setup the log group - const logGroup = new LogGroup(this, 'ApiAccessLogGroup'); - - // Configure API Gateway Access logging - const stage: api.CfnStage = this.api.deploymentStage.node.findChild('Resource') as api.CfnStage; - stage.accessLogSetting = { - destinationArn: logGroup.logGroupArn, - format: "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" - }; - const deployment: api.CfnDeployment = this.api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; - deployment.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W45', - reason: `ApiGateway does have access logging configured as part of AWS::ApiGateway::Stage.` - }] - } - }; + this.api = defaults.GlobalLambdaRestApi(this, this.fn, props.apiGatewayProps); } /** diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/package.json index 10e5292a6..5b4a2d6dc 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-apigateway-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an API Gateway and a Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/__snapshots__/test.apigateway-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/__snapshots__/test.apigateway-lambda.test.js.snap index 23318957b..9596458f6 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/__snapshots__/test.apigateway-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/__snapshots__/test.apigateway-lambda.test.js.snap @@ -3,14 +3,14 @@ exports[`Pattern deployment with existing Lambda function 1`] = ` Object { "Outputs": Object { - "RestApiEndpoint0551178A": Object { + "testapigatewaylambdaLambdaRestApiEndpoint2EF0B753": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", }, "/", ], @@ -45,15 +45,1170 @@ Object { }, }, "Resources": Object { - "ApiAccessLogGroupCEA70788": Object { + "ExistingLambdaFunctionF606C520": Object { + "DependsOn": Array [ + "ExistingLambdaFunctionServiceRole7CC6DE65", + ], + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionServiceRole7CC6DE65", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "ExistingLambdaFunctionServiceRole7CC6DE65": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "ManagedPolicyArns": Array [ + Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + ], + ], + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testapigatewaylambdaApiAccessLogGroupEB3253A2": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "testapigatewaylambdaLambdaRestApiANY1FACA749": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + "RootResourceId", + ], + }, + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, + "testapigatewaylambdaLambdaRestApiANYApiPermissionTesttestapigatewaylambdaLambdaRestApi5DDE3360ANYF71F5CAC": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/test-invoke-stage/*/", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiANYApiPermissiontestapigatewaylambdaLambdaRestApi5DDE3360ANY0CAB129B": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "/*/", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiAccount0D88B6B8": Object { + "DependsOn": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testapigatewaylambdaLambdaRestApiDeployment85334BB3ec6848f57ed1b1aac179df734f57dcaa": Object { + "DependsOn": Array [ + "testapigatewaylambdaLambdaRestApiproxyANYF6150927", + "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + "testapigatewaylambdaLambdaRestApiANY1FACA749", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W45", + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", + }, + ], + }, + }, + "Properties": Object { + "Description": "Automatically created by the RestApi construct", + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Deployment", + }, + "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247": Object { + "Properties": Object { + "AccessLogSetting": Object { + "DestinationArn": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaApiAccessLogGroupEB3253A2", + "Arn", + ], + }, + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", + }, + "DeploymentId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeployment85334BB3ec6848f57ed1b1aac179df734f57dcaa", + }, + "MethodSettings": Array [ + Object { + "DataTraceEnabled": true, + "HttpMethod": "*", + "LoggingLevel": "INFO", + "ResourcePath": "/*", + }, + ], + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "StageName": "prod", + }, + "Type": "AWS::ApiGateway::Stage", + }, + "testapigatewaylambdaLambdaRestApiE957E944": Object { + "Properties": Object { + "EndpointConfiguration": Object { + "Types": Array [ + "EDGE", + ], + }, + "Name": "LambdaRestApi", + }, + "Type": "AWS::ApiGateway::RestApi", + }, + "testapigatewaylambdaLambdaRestApiUsagePlan658131E3": Object { + "Properties": Object { + "ApiStages": Array [ + Object { + "ApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "Stage": Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "Throttle": Object {}, + }, + ], + }, + "Type": "AWS::ApiGateway::UsagePlan", + }, + "testapigatewaylambdaLambdaRestApiproxy2C2C544E": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestapigatewaylambdaLambdaRestApi5DDE3360ANYproxyBA241600": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/test-invoke-stage/*/{proxy+}", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestapigatewaylambdaLambdaRestApi5DDE3360ANYproxyCC830169": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "/*/{proxy+}", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiproxyANYF6150927": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionF606C520", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + }, + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, + }, +} +`; + +exports[`Pattern deployment with new Lambda function 1`] = ` +Object { + "Outputs": Object { + "testapigatewaylambdaLambdaRestApiEndpoint2EF0B753": Object { + "Value": Object { + "Fn::Join": Array [ + "", + Array [ + "https://", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + ".execute-api.", + Object { + "Ref": "AWS::Region", + }, + ".", + Object { + "Ref": "AWS::URLSuffix", + }, + "/", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "/", + ], + ], + }, + }, + }, + "Parameters": Object { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { + "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { + "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { + "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + }, + "Resources": Object { + "testapigatewaylambdaApiAccessLogGroupEB3253A2": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "testapigatewaylambdaLambdaFunction18FF222F": Object { + "DependsOn": Array [ + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testapigatewaylambdaLambdaRestApiANY1FACA749": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + "RootResourceId", + ], + }, + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, + "testapigatewaylambdaLambdaRestApiANYApiPermissionTesttestapigatewaylambdaLambdaRestApi5DDE3360ANYF71F5CAC": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/test-invoke-stage/*/", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiANYApiPermissiontestapigatewaylambdaLambdaRestApi5DDE3360ANY0CAB129B": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "/*/", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiAccount0D88B6B8": Object { + "DependsOn": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testapigatewaylambdaLambdaRestApiDeployment85334BB3a1765c45928980e423727978265730d1": Object { + "DependsOn": Array [ + "testapigatewaylambdaLambdaRestApiproxyANYF6150927", + "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + "testapigatewaylambdaLambdaRestApiANY1FACA749", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W45", + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", + }, + ], + }, + }, + "Properties": Object { + "Description": "Automatically created by the RestApi construct", + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Deployment", + }, + "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247": Object { + "Properties": Object { + "AccessLogSetting": Object { + "DestinationArn": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaApiAccessLogGroupEB3253A2", + "Arn", + ], + }, + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", + }, + "DeploymentId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeployment85334BB3a1765c45928980e423727978265730d1", + }, + "MethodSettings": Array [ + Object { + "DataTraceEnabled": true, + "HttpMethod": "*", + "LoggingLevel": "INFO", + "ResourcePath": "/*", + }, + ], + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "StageName": "prod", + }, + "Type": "AWS::ApiGateway::Stage", + }, + "testapigatewaylambdaLambdaRestApiE957E944": Object { + "Properties": Object { + "EndpointConfiguration": Object { + "Types": Array [ + "EDGE", + ], + }, + "Name": "LambdaRestApi", + }, + "Type": "AWS::ApiGateway::RestApi", + }, + "testapigatewaylambdaLambdaRestApiUsagePlan658131E3": Object { + "Properties": Object { + "ApiStages": Array [ + Object { + "ApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "Stage": Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "Throttle": Object {}, + }, + ], + }, + "Type": "AWS::ApiGateway::UsagePlan", + }, + "testapigatewaylambdaLambdaRestApiproxy2C2C544E": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaRestApiE957E944", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestapigatewaylambdaLambdaRestApi5DDE3360ANYproxyBA241600": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/test-invoke-stage/*/{proxy+}", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestapigatewaylambdaLambdaRestApi5DDE3360ANYproxyCC830169": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":execute-api:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + "/", + Object { + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247", + }, + "/*/{proxy+}", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "testapigatewaylambdaLambdaRestApiproxyANYF6150927": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "testapigatewaylambdaLambdaFunction18FF222F", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + }, + "RestApiId": Object { + "Ref": "testapigatewaylambdaLambdaRestApiE957E944", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, + }, +} +`; + +exports[`Pattern deployment with two ApiGatewayToLambda constructs 1`] = ` +Object { + "Outputs": Object { + "pattern1LambdaRestApiEndpointECE66433": Object { + "Value": Object { + "Fn::Join": Array [ + "", + Array [ + "https://", + Object { + "Ref": "pattern1LambdaRestApi6083801A", + }, + ".execute-api.", + Object { + "Ref": "AWS::Region", + }, + ".", + Object { + "Ref": "AWS::URLSuffix", + }, + "/", + Object { + "Ref": "pattern1LambdaRestApiDeploymentStageprodFF2B9A97", + }, + "/", + ], + ], + }, + }, + "pattern2LambdaRestApiEndpoint47B2C6C6": Object { + "Value": Object { + "Fn::Join": Array [ + "", + Array [ + "https://", + Object { + "Ref": "pattern2LambdaRestApi7106C394", + }, + ".execute-api.", + Object { + "Ref": "AWS::Region", + }, + ".", + Object { + "Ref": "AWS::URLSuffix", + }, + "/", + Object { + "Ref": "pattern2LambdaRestApiDeploymentStageprod134BC514", + }, + "/", + ], + ], + }, + }, + }, + "Parameters": Object { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { + "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { + "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { + "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + }, + "Resources": Object { + "pattern1ApiAccessLogGroupE3E8C305": Object { "DeletionPolicy": "Retain", "Type": "AWS::Logs::LogGroup", "UpdateReplacePolicy": "Retain", }, - "ExistingLambdaFunctionF606C520": Object { + "pattern1LambdaFunction4AE2BC2A": Object { "DependsOn": Array [ - "ExistingLambdaFunctionServiceRole7CC6DE65", + "pattern1LambdaFunctionServiceRoleEEE9B913", ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, "Properties": Object { "Code": Object { "S3Bucket": Object { @@ -93,10 +1248,15 @@ Object { ], }, }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + }, + }, "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionServiceRole7CC6DE65", + "pattern1LambdaFunctionServiceRoleEEE9B913", "Arn", ], }, @@ -104,7 +1264,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "ExistingLambdaFunctionServiceRole7CC6DE65": Object { + "pattern1LambdaFunctionServiceRoleEEE9B913": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -118,51 +1278,6 @@ Object { ], "Version": "2012-10-17", }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, "Policies": Array [ Object { "PolicyDocument": Object { @@ -171,11 +1286,7 @@ Object { "Action": Array [ "logs:CreateLogGroup", "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", ], "Effect": "Allow", "Resource": Object { @@ -190,7 +1301,7 @@ Object { Object { "Ref": "AWS::AccountId", }, - ":*", + ":log-group:/aws/lambda/*", ], ], }, @@ -198,24 +1309,24 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + "PolicyName": "LambdaFunctionServiceRolePolicy", }, ], }, "Type": "AWS::IAM::Role", }, - "RestApi0C43BF4B": Object { + "pattern1LambdaRestApi6083801A": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "EDGE", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "pattern1LambdaRestApiANY1CAD2ADA": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -237,7 +1348,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -248,22 +1359,22 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "pattern1LambdaRestApi6083801A", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionRestApiANY3A99B4EE": Object { + "pattern1LambdaRestApiANYApiPermissionTestpattern1LambdaRestApi3E9A122CANYFC4F7B13": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -286,25 +1397,21 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern1LambdaRestApi6083801A", }, - "/*/", + "/test-invoke-stage/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestRestApiANY79BD91F2": Object { + "pattern1LambdaRestApiANYApiPermissionpattern1LambdaRestApi3E9A122CANY5D85A817": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -327,27 +1434,100 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, - "/test-invoke-stage/*/", + "/", + Object { + "Ref": "pattern1LambdaRestApiDeploymentStageprodFF2B9A97", + }, + "/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiDeployment180EC503e06cd95e76bb0f117b881703f487bbf5": Object { + "pattern1LambdaRestApiAccount52947E66": Object { + "DependsOn": Array [ + "pattern1LambdaRestApi6083801A", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "pattern1LambdaRestApiCloudWatchRole41F462A6", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "pattern1LambdaRestApiCloudWatchRole41F462A6": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "pattern1LambdaRestApiDeployment20DFD9B2573799e20d1a348378b393327f9c6e15": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", + "pattern1LambdaRestApiproxyANY9D2D185B", + "pattern1LambdaRestApiproxy6E65FF1B", + "pattern1LambdaRestApiANY1CAD2ADA", ], "Metadata": Object { "cfn_nag": Object { "rules_to_suppress": Array [ Object { "id": "W45", - "reason": "ApiGateway does have access logging configured as part of AWS::ApiGateway::Stage.", + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", }, ], }, @@ -355,24 +1535,24 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "pattern1LambdaRestApiDeploymentStageprodFF2B9A97": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { "Fn::GetAtt": Array [ - "testapigatewaylambdaApiAccessLogGroupEB3253A2", + "pattern1ApiAccessLogGroupE3E8C305", "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503e06cd95e76bb0f117b881703f487bbf5", + "Ref": "pattern1LambdaRestApiDeployment20DFD9B2573799e20d1a348378b393327f9c6e15", }, "MethodSettings": Array [ Object { @@ -383,21 +1563,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiUsagePlan6E1C537A": Object { + "pattern1LambdaRestApiUsagePlan77521F91": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern1LambdaRestApiDeploymentStageprodFF2B9A97", }, "Throttle": Object {}, }, @@ -405,7 +1585,22 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "pattern1LambdaRestApiproxy6E65FF1B": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "pattern1LambdaRestApi6083801A", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "pattern1LambdaRestApi6083801A", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "pattern1LambdaRestApiproxyANY9D2D185B": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -427,7 +1622,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -437,20 +1632,20 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "pattern1LambdaRestApiproxy6E65FF1B", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionRestApiANYproxy9C9912F9": Object { + "pattern1LambdaRestApiproxyANYApiPermissionTestpattern1LambdaRestApi3E9A122CANYproxy0211E18E": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -471,27 +1666,23 @@ Object { Object { "Ref": "AWS::AccountId", }, - ":", - Object { - "Ref": "RestApi0C43BF4B", - }, - "/", + ":", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern1LambdaRestApi6083801A", }, - "/*/{proxy+}", + "/test-invoke-stage/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestRestApiANYproxyCB7BC56D": Object { + "pattern1LambdaRestApiproxyANYApiPermissionpattern1LambdaRestApi3E9A122CANYproxy35F22AD4": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "ExistingLambdaFunctionF606C520", + "pattern1LambdaFunction4AE2BC2A", "Arn", ], }, @@ -514,95 +1705,27 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern1LambdaRestApi6083801A", }, - "/test-invoke-stage/*/{proxy+}", + "/", + Object { + "Ref": "pattern1LambdaRestApiDeploymentStageprodFF2B9A97", + }, + "/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, - "testapigatewaylambdaApiAccessLogGroupEB3253A2": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "RetentionInDays": 731, - }, - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, - }, -} -`; - -exports[`Pattern deployment with new Lambda function 1`] = ` -Object { - "Outputs": Object { - "RestApiEndpoint0551178A": Object { - "Value": Object { - "Fn::Join": Array [ - "", - Array [ - "https://", - Object { - "Ref": "RestApi0C43BF4B", - }, - ".execute-api.", - Object { - "Ref": "AWS::Region", - }, - ".", - Object { - "Ref": "AWS::URLSuffix", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", - }, - "/", - ], - ], - }, - }, - }, - "Parameters": Object { - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { - "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { - "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { - "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - }, - "Resources": Object { - "ApiAccessLogGroupCEA70788": Object { + "pattern2ApiAccessLogGroup6E2029E1": Object { "DeletionPolicy": "Retain", "Type": "AWS::Logs::LogGroup", "UpdateReplacePolicy": "Retain", }, - "LambdaFunctionBF21E41F": Object { + "pattern2LambdaFunction20E7E90C": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "pattern2LambdaFunctionServiceRoleF8D0D0F1", ], "Metadata": Object { "cfn_nag": Object { @@ -661,7 +1784,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "pattern2LambdaFunctionServiceRoleF8D0D0F1", "Arn", ], }, @@ -669,7 +1792,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "pattern2LambdaFunctionServiceRoleF8D0D0F1": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -720,87 +1843,18 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "RestApi0C43BF4B": Object { + "pattern2LambdaRestApi7106C394": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "EDGE", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "pattern2LambdaRestApiANY3965E74E": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -822,7 +1876,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -833,22 +1887,22 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "pattern2LambdaRestApi7106C394", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionRestApiANY3A99B4EE": Object { + "pattern2LambdaRestApiANYApiPermissionTestpattern2LambdaRestApiA2DE99CBANY576A0FE3": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -871,25 +1925,21 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern2LambdaRestApi7106C394", }, - "/*/", + "/test-invoke-stage/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestRestApiANY79BD91F2": Object { + "pattern2LambdaRestApiANYApiPermissionpattern2LambdaRestApiA2DE99CBANYBCC44A2F": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -912,27 +1962,100 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, - "/test-invoke-stage/*/", + "/", + Object { + "Ref": "pattern2LambdaRestApiDeploymentStageprod134BC514", + }, + "/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": Object { + "pattern2LambdaRestApiAccount4E75931C": Object { + "DependsOn": Array [ + "pattern2LambdaRestApi7106C394", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "pattern2LambdaRestApiCloudWatchRoleCF2A5520", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "pattern2LambdaRestApiCloudWatchRoleCF2A5520": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "pattern2LambdaRestApiDeployment016BF0A2ac361352807d6a8d0a15c582caf0e0e8": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", + "pattern2LambdaRestApiproxyANY4C5559C6", + "pattern2LambdaRestApiproxy541AAB3E", + "pattern2LambdaRestApiANY3965E74E", ], "Metadata": Object { "cfn_nag": Object { "rules_to_suppress": Array [ Object { "id": "W45", - "reason": "ApiGateway does have access logging configured as part of AWS::ApiGateway::Stage.", + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", }, ], }, @@ -940,24 +2063,24 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "pattern2LambdaRestApiDeploymentStageprod134BC514": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { "Fn::GetAtt": Array [ - "testapigatewaylambdaApiAccessLogGroupEB3253A2", + "pattern2ApiAccessLogGroup6E2029E1", "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8", + "Ref": "pattern2LambdaRestApiDeployment016BF0A2ac361352807d6a8d0a15c582caf0e0e8", }, "MethodSettings": Array [ Object { @@ -968,21 +2091,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiUsagePlan6E1C537A": Object { + "pattern2LambdaRestApiUsagePlanBA5CA2BD": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern2LambdaRestApiDeploymentStageprod134BC514", }, "Throttle": Object {}, }, @@ -990,7 +2113,22 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "pattern2LambdaRestApiproxy541AAB3E": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "pattern2LambdaRestApi7106C394", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "pattern2LambdaRestApi7106C394", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "pattern2LambdaRestApiproxyANY4C5559C6": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -1012,7 +2150,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -1022,20 +2160,20 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "pattern2LambdaRestApiproxy541AAB3E", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionRestApiANYproxy9C9912F9": Object { + "pattern2LambdaRestApiproxyANYApiPermissionTestpattern2LambdaRestApiA2DE99CBANYproxy309B7F1D": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -1058,25 +2196,21 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "pattern2LambdaRestApi7106C394", }, - "/*/{proxy+}", + "/test-invoke-stage/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestRestApiANYproxyCB7BC56D": Object { + "pattern2LambdaRestApiproxyANYApiPermissionpattern2LambdaRestApiA2DE99CBANYproxyD2FED300": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "pattern2LambdaFunction20E7E90C", "Arn", ], }, @@ -1099,38 +2233,19 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "pattern2LambdaRestApi7106C394", }, - "/test-invoke-stage/*/{proxy+}", + "/", + Object { + "Ref": "pattern2LambdaRestApiDeploymentStageprod134BC514", + }, + "/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, - "testapigatewaylambdaApiAccessLogGroupEB3253A2": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "RetentionInDays": 731, - }, - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.deployFunction.expected.json index 90ccde175..316c3cbc5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.deployFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.deployFunction.expected.json @@ -1,15 +1,7 @@ { "Description": "Integration Test for aws-apigateway-lambda", "Resources": { - "testapigatewaylambdaApiAccessLogGroupEB3253A2": { - "Type": "AWS::Logs::LogGroup", - "Properties": { - "RetentionInDays": 731 - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -60,7 +52,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testapigatewaylambdaLambdaFunction18FF222F": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -104,7 +96,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7", "Arn" ] }, @@ -116,7 +108,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testapigatewaylambdaLambdaFunctionServiceRole5CD2E9F7" ], "Metadata": { "cfn_nag": { @@ -129,7 +121,12 @@ } } }, - "RestApi0C43BF4B": { + "testapigatewaylambdaApiAccessLogGroupEB3253A2": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testapigatewaylambdaLambdaRestApiE957E944": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -137,38 +134,38 @@ "EDGE" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": { + "testapigatewaylambdaLambdaRestApiDeployment85334BB3a1765c45928980e423727978265730d1": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94" + "testapigatewaylambdaLambdaRestApiproxyANYF6150927", + "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + "testapigatewaylambdaLambdaRestApiANY1FACA749" ], "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W45", - "reason": "ApiGateway does have access logging configured as part of AWS::ApiGateway::Stage." + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource" } ] } } }, - "RestApiDeploymentStageprod3855DE66": { + "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AccessLogSetting": { "DestinationArn": { @@ -177,10 +174,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8" + "Ref": "testapigatewaylambdaLambdaRestApiDeployment85334BB3a1765c45928980e423727978265730d1" }, "MethodSettings": [ { @@ -193,28 +190,28 @@ "StageName": "prod" } }, - "RestApiproxyC95856DD": { + "testapigatewaylambdaLambdaRestApiproxy2C2C544E": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testapigatewaylambdaLambdaRestApiE957E944", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" } } }, - "RestApiproxyANYApiPermissiontestapigatewaylambdaRestApi54300087ANYproxy2DB4C4FC": { + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestapigatewaylambdaLambdaRestApiF9D18CB1ANYproxy7C4BA4BF": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -237,11 +234,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/*/{proxy+}" ] @@ -249,13 +246,13 @@ } } }, - "RestApiproxyANYApiPermissionTesttestapigatewaylambdaRestApi54300087ANYproxy9A552081": { + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestapigatewaylambdaLambdaRestApiF9D18CB1ANYproxy645DE979": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -278,7 +275,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/test-invoke-stage/*/{proxy+}" ] @@ -286,15 +283,15 @@ } } }, - "RestApiproxyANY1786B242": { + "testapigatewaylambdaLambdaRestApiproxyANYF6150927": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "testapigatewaylambdaLambdaRestApiproxy2C2C544E" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -315,7 +312,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -326,13 +323,13 @@ } } }, - "RestApiANYApiPermissiontestapigatewaylambdaRestApi54300087ANY87811EBD": { + "testapigatewaylambdaLambdaRestApiANYApiPermissiontestapigatewaylambdaLambdaRestApiF9D18CB1ANY2122E1BB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -355,11 +352,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/*/" ] @@ -367,13 +364,13 @@ } } }, - "RestApiANYApiPermissionTesttestapigatewaylambdaRestApi54300087ANY855753FC": { + "testapigatewaylambdaLambdaRestApiANYApiPermissionTesttestapigatewaylambdaLambdaRestApiF9D18CB1ANY647E8305": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -396,7 +393,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/test-invoke-stage/*/" ] @@ -404,18 +401,18 @@ } } }, - "RestApiANYA7C1DC94": { + "testapigatewaylambdaLambdaRestApiANY1FACA749": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testapigatewaylambdaLambdaRestApiE957E944", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -436,7 +433,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testapigatewaylambdaLambdaFunction18FF222F", "Arn" ] }, @@ -447,28 +444,23 @@ } } }, - "RestApiUsagePlan6E1C537A": { + "testapigatewaylambdaLambdaRestApiUsagePlan658131E3": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "Stage": { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "Throttle": {} } ] } }, - "ApiAccessLogGroupCEA70788": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaRestApiCloudWatchRoleF339D4E6": { + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -523,44 +515,30 @@ ] } }, - "LambdaRestApiAccount": { + "testapigatewaylambdaLambdaRestApiAccount0D88B6B8": { "Type": "AWS::ApiGateway::Account", "Properties": { "CloudWatchRoleArn": { "Fn::GetAtt": [ - "LambdaRestApiCloudWatchRoleF339D4E6", + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039", "Arn" ] } }, "DependsOn": [ - "RestApi0C43BF4B" + "testapigatewaylambdaLambdaRestApiE957E944" ] } }, - "Parameters": { - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": { - "Type": "String", - "Description": "S3 bucket for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": { - "Type": "String", - "Description": "S3 key for asset version \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": { - "Type": "String", - "Description": "Artifact hash for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" - } - }, "Outputs": { - "RestApiEndpoint0551178A": { + "testapigatewaylambdaLambdaRestApiEndpoint2EF0B753": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, ".execute-api.", { @@ -572,12 +550,26 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/" ] ] } } + }, + "Parameters": { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": { + "Type": "String", + "Description": "S3 bucket for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": { + "Type": "String", + "Description": "S3 key for asset version \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": { + "Type": "String", + "Description": "Artifact hash for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.existingFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.existingFunction.expected.json index 8cd444c91..a158223f0 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.existingFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/integ.existingFunction.expected.json @@ -123,13 +123,10 @@ }, "testapigatewaylambdaApiAccessLogGroupEB3253A2": { "Type": "AWS::Logs::LogGroup", - "Properties": { - "RetentionInDays": 731 - }, "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "RestApi0C43BF4B": { + "testapigatewaylambdaLambdaRestApiE957E944": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -137,38 +134,38 @@ "EDGE" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": { + "testapigatewaylambdaLambdaRestApiDeployment85334BB3938813331492485ced06ab87062fb015": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94" + "testapigatewaylambdaLambdaRestApiproxyANYF6150927", + "testapigatewaylambdaLambdaRestApiproxy2C2C544E", + "testapigatewaylambdaLambdaRestApiANY1FACA749" ], "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W45", - "reason": "ApiGateway does have access logging configured as part of AWS::ApiGateway::Stage." + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource" } ] } } }, - "RestApiDeploymentStageprod3855DE66": { + "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AccessLogSetting": { "DestinationArn": { @@ -177,10 +174,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8" + "Ref": "testapigatewaylambdaLambdaRestApiDeployment85334BB3938813331492485ced06ab87062fb015" }, "MethodSettings": [ { @@ -193,22 +190,22 @@ "StageName": "prod" } }, - "RestApiproxyC95856DD": { + "testapigatewaylambdaLambdaRestApiproxy2C2C544E": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testapigatewaylambdaLambdaRestApiE957E944", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" } } }, - "RestApiproxyANYApiPermissiontestapigatewaylambdaRestApi54300087ANYproxy2DB4C4FC": { + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestapigatewaylambdaLambdaRestApiF9D18CB1ANYproxy7C4BA4BF": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -237,11 +234,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/*/{proxy+}" ] @@ -249,7 +246,7 @@ } } }, - "RestApiproxyANYApiPermissionTesttestapigatewaylambdaRestApi54300087ANYproxy9A552081": { + "testapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestapigatewaylambdaLambdaRestApiF9D18CB1ANYproxy645DE979": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -278,7 +275,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/test-invoke-stage/*/{proxy+}" ] @@ -286,15 +283,15 @@ } } }, - "RestApiproxyANY1786B242": { + "testapigatewaylambdaLambdaRestApiproxyANYF6150927": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "testapigatewaylambdaLambdaRestApiproxy2C2C544E" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -326,7 +323,7 @@ } } }, - "RestApiANYApiPermissiontestapigatewaylambdaRestApi54300087ANY87811EBD": { + "testapigatewaylambdaLambdaRestApiANYApiPermissiontestapigatewaylambdaLambdaRestApiF9D18CB1ANY2122E1BB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -355,11 +352,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/*/" ] @@ -367,7 +364,7 @@ } } }, - "RestApiANYApiPermissionTesttestapigatewaylambdaRestApi54300087ANY855753FC": { + "testapigatewaylambdaLambdaRestApiANYApiPermissionTesttestapigatewaylambdaLambdaRestApiF9D18CB1ANY647E8305": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -396,7 +393,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "/test-invoke-stage/*/" ] @@ -404,18 +401,18 @@ } } }, - "RestApiANYA7C1DC94": { + "testapigatewaylambdaLambdaRestApiANY1FACA749": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testapigatewaylambdaLambdaRestApiE957E944", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -447,28 +444,23 @@ } } }, - "RestApiUsagePlan6E1C537A": { + "testapigatewaylambdaLambdaRestApiUsagePlan658131E3": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, "Stage": { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "Throttle": {} } ] } }, - "ApiAccessLogGroupCEA70788": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaRestApiCloudWatchRoleF339D4E6": { + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -523,18 +515,18 @@ ] } }, - "LambdaRestApiAccount": { + "testapigatewaylambdaLambdaRestApiAccount0D88B6B8": { "Type": "AWS::ApiGateway::Account", "Properties": { "CloudWatchRoleArn": { "Fn::GetAtt": [ - "LambdaRestApiCloudWatchRoleF339D4E6", + "testapigatewaylambdaLambdaRestApiCloudWatchRole6D45E039", "Arn" ] } }, "DependsOn": [ - "RestApi0C43BF4B" + "testapigatewaylambdaLambdaRestApiE957E944" ] } }, @@ -553,14 +545,14 @@ } }, "Outputs": { - "RestApiEndpoint0551178A": { + "testapigatewaylambdaLambdaRestApiEndpoint2EF0B753": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "testapigatewaylambdaLambdaRestApiE957E944" }, ".execute-api.", { @@ -572,7 +564,7 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testapigatewaylambdaLambdaRestApiDeploymentStageprod4EBF7247" }, "/" ] diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts index c2e23ae31..56ee9442c 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts @@ -135,4 +135,34 @@ test('Error on deployLambda=true and lambdaFunctionProps=undefined', () => { }; // Assertion 1 expect(app).toThrowError(); +}); + +// -------------------------------------------------------------- +// Pattern deployment with two ApiGatewayToLambda constructs +// -------------------------------------------------------------- +test('Pattern deployment with two ApiGatewayToLambda constructs', () => { + // Initial Setup + const stack = new Stack(); + const props1: ApiGatewayToLambdaProps = { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + } + }; + new ApiGatewayToLambda(stack, 'pattern1', props1); + + const props2: ApiGatewayToLambdaProps = { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + } + }; + new ApiGatewayToLambda(stack, 'pattern2', props2); + + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/lib/index.ts index bac3b0681..22f53eeef 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/lib/index.ts @@ -102,12 +102,12 @@ export class ApiGatewayToSqs extends Construct { super(scope, id); // Setup the encryption key - this.encryptionKey = defaults.buildEncryptionKey(scope, props.encryptionKeyProps); + this.encryptionKey = defaults.buildEncryptionKey(this, props.encryptionKeyProps); // Setup the dead letter queue, if applicable let dlqi: sqs.DeadLetterQueue | undefined; if (!props.deployDeadLetterQueue || props.deployDeadLetterQueue === true) { - const dlq: sqs.Queue = defaults.buildQueue(scope, 'deadLetterQueue', { + const dlq: sqs.Queue = defaults.buildQueue(this, 'deadLetterQueue', { encryptionKey: this.encryptionKey, queueProps: props.queueProps }); @@ -118,7 +118,7 @@ export class ApiGatewayToSqs extends Construct { } // Setup the queue - this.queue = defaults.buildQueue(scope, 'queue', { + this.queue = defaults.buildQueue(this, 'queue', { encryptionKey: this.encryptionKey, queueProps: props.queueProps, deadLetterQueue: dlqi diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/package.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/package.json index bc71d33cd..f43cb2d80 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-apigateway-sqs", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,15 +52,16 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,11 +71,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/__snapshots__/apigateway-sqs.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/__snapshots__/apigateway-sqs.test.js.snap index e1ea9320a..2da122a15 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/__snapshots__/apigateway-sqs.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/__snapshots__/apigateway-sqs.test.js.snap @@ -31,7 +31,12 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { + "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "apigatewaysqsEncryptionKey4A698F7C": Object { "DeletionPolicy": "Retain", "Properties": Object { "EnableKeyRotation": true, @@ -101,11 +106,6 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { - "DeletionPolicy": "Retain", - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, "apigatewaysqsLambdaRestApiAccount8FA59342": Object { "DependsOn": Array [ "apigatewaysqsRestApi03BFD711", @@ -186,7 +186,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "apigatewaysqsRestApiDeployment823C310Bb49e111d67a99651ecb38dc4ffc69e8b": Object { + "apigatewaysqsRestApiDeployment823C310Bb3eb8381f81a14298ee8e133d94084e4": Object { "DependsOn": Array [ "apigatewaysqsRestApiGET13C64342", "apigatewaysqsRestApimessageDELETE46195B92", @@ -220,10 +220,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "apigatewaysqsRestApiDeployment823C310Bb49e111d67a99651ecb38dc4ffc69e8b", + "Ref": "apigatewaysqsRestApiDeployment823C310Bb3eb8381f81a14298ee8e133d94084e4", }, "MethodSettings": Array [ Object { @@ -291,7 +291,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -376,7 +376,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -492,7 +492,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -554,7 +554,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, @@ -564,7 +564,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -574,7 +574,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -584,7 +584,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -601,29 +601,29 @@ Object { }, "Type": "AWS::IAM::Policy", }, - "deadLetterQueue3F848E28": Object { + "apigatewaysqsdeadLetterQueue25B510FA": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, }, "Type": "AWS::SQS::Queue", }, - "queue276F7297": Object { + "apigatewaysqsqueueE186B895": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, "RedrivePolicy": Object { "deadLetterTargetArn": Object { "Fn::GetAtt": Array [ - "deadLetterQueue3F848E28", + "apigatewaysqsdeadLetterQueue25B510FA", "Arn", ], }, @@ -667,7 +667,12 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { + "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "apigatewaysqsEncryptionKey4A698F7C": Object { "DeletionPolicy": "Retain", "Properties": Object { "EnableKeyRotation": true, @@ -737,11 +742,6 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { - "DeletionPolicy": "Retain", - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, "apigatewaysqsLambdaRestApiAccount8FA59342": Object { "DependsOn": Array [ "apigatewaysqsRestApi03BFD711", @@ -822,7 +822,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "apigatewaysqsRestApiDeployment823C310Bb49e111d67a99651ecb38dc4ffc69e8b": Object { + "apigatewaysqsRestApiDeployment823C310Bb3eb8381f81a14298ee8e133d94084e4": Object { "DependsOn": Array [ "apigatewaysqsRestApiGET13C64342", "apigatewaysqsRestApimessageDELETE46195B92", @@ -856,10 +856,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "apigatewaysqsRestApiDeployment823C310Bb49e111d67a99651ecb38dc4ffc69e8b", + "Ref": "apigatewaysqsRestApiDeployment823C310Bb3eb8381f81a14298ee8e133d94084e4", }, "MethodSettings": Array [ Object { @@ -927,7 +927,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -1012,7 +1012,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -1128,7 +1128,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -1190,7 +1190,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, @@ -1200,7 +1200,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -1210,7 +1210,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -1220,7 +1220,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -1237,29 +1237,29 @@ Object { }, "Type": "AWS::IAM::Policy", }, - "deadLetterQueue3F848E28": Object { + "apigatewaysqsdeadLetterQueue25B510FA": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, }, "Type": "AWS::SQS::Queue", }, - "queue276F7297": Object { + "apigatewaysqsqueueE186B895": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, "RedrivePolicy": Object { "deadLetterTargetArn": Object { "Fn::GetAtt": Array [ - "deadLetterQueue3F848E28", + "apigatewaysqsdeadLetterQueue25B510FA", "Arn", ], }, @@ -1303,7 +1303,12 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { + "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "apigatewaysqsEncryptionKey4A698F7C": Object { "DeletionPolicy": "Retain", "Properties": Object { "EnableKeyRotation": true, @@ -1373,11 +1378,6 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "apigatewaysqsApiAccessLogGroup4D14D1D7": Object { - "DeletionPolicy": "Retain", - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, "apigatewaysqsLambdaRestApiAccount8FA59342": Object { "DependsOn": Array [ "apigatewaysqsRestApi03BFD711", @@ -1458,7 +1458,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "apigatewaysqsRestApiDeployment823C310B94660621187ecc4f60bbf8643bc7537d": Object { + "apigatewaysqsRestApiDeployment823C310B81c8c99dceff06c656282a644dc22b99": Object { "DependsOn": Array [ "apigatewaysqsRestApiGET13C64342", "apigatewaysqsRestApimessageC2D606D3", @@ -1490,10 +1490,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "apigatewaysqsRestApiDeployment823C310B94660621187ecc4f60bbf8643bc7537d", + "Ref": "apigatewaysqsRestApiDeployment823C310B81c8c99dceff06c656282a644dc22b99", }, "MethodSettings": Array [ Object { @@ -1561,7 +1561,7 @@ Object { "/", Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "QueueName", ], }, @@ -1657,7 +1657,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, @@ -1667,7 +1667,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "apigatewaysqsqueueE186B895", "Arn", ], }, @@ -1684,29 +1684,29 @@ Object { }, "Type": "AWS::IAM::Policy", }, - "deadLetterQueue3F848E28": Object { + "apigatewaysqsdeadLetterQueue25B510FA": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, }, "Type": "AWS::SQS::Queue", }, - "queue276F7297": Object { + "apigatewaysqsqueueE186B895": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "apigatewaysqsEncryptionKey4A698F7C", "Arn", ], }, "RedrivePolicy": Object { "deadLetterTargetArn": Object { "Fn::GetAtt": Array [ - "deadLetterQueue3F848E28", + "apigatewaysqsdeadLetterQueue25B510FA", "Arn", ], }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.expected.json index da2041d5e..e8c175405 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.expected.json @@ -1,6 +1,112 @@ { "Description": "Integration Test for aws-apigateway-sqs", "Resources": { + "testapigatewaysqsEncryptionKeyFD2F56B1": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "testapigatewaysqsapigatewayrole07110CD6", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testapigatewaysqsdeadLetterQueueAA4F6060": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": { + "Fn::GetAtt": [ + "testapigatewaysqsEncryptionKeyFD2F56B1", + "Arn" + ] + } + } + }, + "testapigatewaysqsqueue8EDC3CAF": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": { + "Fn::GetAtt": [ + "testapigatewaysqsEncryptionKeyFD2F56B1", + "Arn" + ] + }, + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testapigatewaysqsdeadLetterQueueAA4F6060", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + } + }, + "testapigatewaysqsApiAccessLogGroup37AB0350": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, "testapigatewaysqsRestApi557C7EDC": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -12,7 +118,7 @@ "Name": "RestApi" } }, - "testapigatewaysqsRestApiDeploymentCA19D372c3b49be7d97efd65e90b7b5084cd80d8": { + "testapigatewaysqsRestApiDeploymentCA19D3723284170350125cf6cf25e30c33a57efd": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -50,10 +156,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testapigatewaysqsRestApiDeploymentCA19D372c3b49be7d97efd65e90b7b5084cd80d8" + "Ref": "testapigatewaysqsRestApiDeploymentCA19D3723284170350125cf6cf25e30c33a57efd" }, "MethodSettings": [ { @@ -139,7 +245,7 @@ "/", { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "QueueName" ] } @@ -224,7 +330,7 @@ "/", { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "QueueName" ] } @@ -309,7 +415,7 @@ "/", { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "QueueName" ] } @@ -349,11 +455,6 @@ ] } }, - "testapigatewaysqsApiAccessLogGroup37AB0350": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testapigatewaysqsLambdaRestApiCloudWatchRoleF10D0F78": { "Type": "AWS::IAM::Role", "Properties": { @@ -455,7 +556,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testapigatewaysqsEncryptionKeyFD2F56B1", "Arn" ] } @@ -465,7 +566,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "Arn" ] } @@ -475,7 +576,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "Arn" ] } @@ -485,7 +586,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsqueue8EDC3CAF", "Arn" ] } @@ -500,107 +601,6 @@ } ] } - }, - "EncryptionKey1B843E66": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "testapigatewaysqsapigatewayrole07110CD6", - "Arn" - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "EnableKeyRotation": true - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "deadLetterQueue3F848E28": { - "Type": "AWS::SQS::Queue", - "Properties": { - "KmsMasterKeyId": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } - } - }, - "queue276F7297": { - "Type": "AWS::SQS::Queue", - "Properties": { - "KmsMasterKeyId": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - }, - "RedrivePolicy": { - "deadLetterTargetArn": { - "Fn::GetAtt": [ - "deadLetterQueue3F848E28", - "Arn" - ] - }, - "maxReceiveCount": 3 - } - } } }, "Outputs": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.no-arguments.expected.json index 297d2a80e..92c44fedd 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-apigateway-sqs/test/integ.no-arguments.expected.json @@ -1,6 +1,112 @@ { "Description": "Integration Test for aws-apigateway-sqs", "Resources": { + "testapigatewaysqsdefaultEncryptionKey76707C9E": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "testapigatewaysqsdefaultapigatewayrole080B85EC", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testapigatewaysqsdefaultdeadLetterQueue24467CAD": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": { + "Fn::GetAtt": [ + "testapigatewaysqsdefaultEncryptionKey76707C9E", + "Arn" + ] + } + } + }, + "testapigatewaysqsdefaultqueueCAC098BE": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": { + "Fn::GetAtt": [ + "testapigatewaysqsdefaultEncryptionKey76707C9E", + "Arn" + ] + }, + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testapigatewaysqsdefaultdeadLetterQueue24467CAD", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + } + }, + "testapigatewaysqsdefaultApiAccessLogGroup16132600": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, "testapigatewaysqsdefaultRestApi554243C3": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -12,7 +118,7 @@ "Name": "RestApi" } }, - "testapigatewaysqsdefaultRestApiDeploymentFB9688F515062e1c331d835b42c02aa42f85db7f": { + "testapigatewaysqsdefaultRestApiDeploymentFB9688F5638eca4a0d71dff702d4b2c6b1d1e2df": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -48,10 +154,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testapigatewaysqsdefaultRestApiDeploymentFB9688F515062e1c331d835b42c02aa42f85db7f" + "Ref": "testapigatewaysqsdefaultRestApiDeploymentFB9688F5638eca4a0d71dff702d4b2c6b1d1e2df" }, "MethodSettings": [ { @@ -140,7 +246,7 @@ "/", { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsdefaultqueueCAC098BE", "QueueName" ] } @@ -180,11 +286,6 @@ ] } }, - "testapigatewaysqsdefaultApiAccessLogGroup16132600": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testapigatewaysqsdefaultLambdaRestApiCloudWatchRole8EA3C5EC": { "Type": "AWS::IAM::Role", "Properties": { @@ -286,7 +387,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testapigatewaysqsdefaultEncryptionKey76707C9E", "Arn" ] } @@ -296,7 +397,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testapigatewaysqsdefaultqueueCAC098BE", "Arn" ] } @@ -311,107 +412,6 @@ } ] } - }, - "EncryptionKey1B843E66": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "testapigatewaysqsdefaultapigatewayrole080B85EC", - "Arn" - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "EnableKeyRotation": true - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "deadLetterQueue3F848E28": { - "Type": "AWS::SQS::Queue", - "Properties": { - "KmsMasterKeyId": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } - } - }, - "queue276F7297": { - "Type": "AWS::SQS::Queue", - "Properties": { - "KmsMasterKeyId": { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - }, - "RedrivePolicy": { - "deadLetterTargetArn": { - "Fn::GetAtt": [ - "deadLetterQueue3F848E28", - "Arn" - ] - }, - "maxReceiveCount": 3 - } - } } }, "Outputs": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/README.md index 2f410cda8..1901ce22b 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/README.md @@ -66,12 +66,13 @@ _Parameters_ |lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user provided props to override the default props for Lambda function| |apiGatewayProps?|[`api.LambdaRestApiProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.LambdaRestApiProps.html)|Optional user provided props to override the default props for API Gateway| |cloudFrontDistributionProps?|[`cloudfront.CloudFrontWebDistributionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistributionProps.html)|Optional user provided props to override the default props for Cloudfront Distribution| +|insertHttpSecurityHeaders?|`boolean`|Optional user provided props to turn on/off the automatic injection of best practice HTTP security headers in all resonses from cloudfront| ## Pattern Properties | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct| +|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct| |lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of the Lambda function created by the pattern.| |restApi()|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|Returns an instance of the API Gateway REST API created by the pattern.| diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/lib/index.ts index d2aef5da6..fefc17799 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/lib/index.ts @@ -54,7 +54,14 @@ export interface CloudFrontToApiGatewayToLambdaProps { * * @default - Default props are used */ - readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps + readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any, + /** + * Optional user provided props to turn on/off the automatic injection of best practice HTTP + * security headers in all resonses from cloudfront + * + * @default - true + */ + readonly insertHttpSecurityHeaders?: boolean; } export class CloudFrontToApiGatewayToLambda extends Construct { @@ -73,7 +80,7 @@ export class CloudFrontToApiGatewayToLambda extends Construct { constructor(scope: Construct, id: string, props: CloudFrontToApiGatewayToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -83,14 +90,15 @@ export class CloudFrontToApiGatewayToLambda extends Construct { const apiCloudfront: CloudFrontToApiGateway = new CloudFrontToApiGateway(this, 'CloudFrontToApiGateway', { existingApiGatewayObj: this.api, - cloudFrontDistributionProps: props.cloudFrontDistributionProps + cloudFrontDistributionProps: props.cloudFrontDistributionProps, + insertHttpSecurityHeaders: props.insertHttpSecurityHeaders }); this.cloudfront = apiCloudfront.cloudFrontWebDistribution(); } /** - * @summary Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct. + * @summary Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct. * @returns {cloudfront.CloudFrontWebDistribution} Instance of CloudFrontWebDistribution created by the construct * @since 0.8.0 * @access public @@ -100,7 +108,7 @@ export class CloudFrontToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of api.RestApi created by the construct. + * @summary Returns an instance of api.RestApi created by the construct. * @returns {api.RestApi} Instance of RestApi created by the construct * @since 0.8.0 * @access public @@ -110,7 +118,7 @@ export class CloudFrontToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of Function created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/package.json index 6b23b7d0c..f75483ec6 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Cloudfront to AWS API Gateway to AWS Lambda integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,17 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-solutions-konstruk/aws-cloudfront-apigateway": "~0.8.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-solutions-konstruk/aws-cloudfront-apigateway": "~0.8.1", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-solutions-konstruk/aws-cloudfront-apigateway": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-solutions-konstruk/aws-cloudfront-apigateway": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/__snapshots__/test.cloudfront-apigateway-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/__snapshots__/test.cloudfront-apigateway-lambda.test.js.snap index e9a74b4b5..b48deef2f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/__snapshots__/test.cloudfront-apigateway-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/__snapshots__/test.cloudfront-apigateway-lambda.test.js.snap @@ -3,14 +3,14 @@ exports[`snapshot test CloudFrontToApiGatewayToLambda default params 1`] = ` Object { "Outputs": Object { - "testcloudfrontapigatewaylambdaRestApiEndpoint0A6CB43E": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiEndpoint83FD8F0F": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7", }, "/", ], @@ -45,132 +45,22 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { - "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", - ], + "testcloudfrontapigatewaylambdaApiAccessLogGroup97EB2E40": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewayCloudFrontDistributionCFDistribution4AF2BFE4": Object { "Metadata": Object { "cfn_nag": Object { "rules_to_suppress": Array [ Object { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", - }, - ], - }, - }, - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Environment": Object { - "Variables": Object { - "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", - "Arn", - ], - }, - "Runtime": "nodejs10.x", - }, - "Type": "AWS::Lambda::Function", - }, - "LambdaFunctionServiceRole0C4CDE0B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", }, ], - "Version": "2012-10-17", }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/lambda/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRolePolicy", - }, - ], }, - "Type": "AWS::IAM::Role", - }, - "testcloudfrontapigatewaylambdaApiAccessLogGroup97EB2E40": Object { - "DeletionPolicy": "Retain", - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - }, - "testcloudfrontapigatewaylambdaCloudFrontToApiGatewayCloudFrontDistributionCFDistribution4AF2BFE4": Object { "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -189,6 +79,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion1946ABC2", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -235,7 +133,7 @@ Object { Array [ "https://", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, ".execute-api.", Object { @@ -247,7 +145,7 @@ Object { }, "/", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7", }, "/", ], @@ -312,21 +210,36 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, - "testcloudfrontapigatewaylambdaLambdaRestApiAccount1A4578BB": Object { + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeaders6945414A": Object { "DependsOn": Array [ - "testcloudfrontapigatewaylambdaRestApi96B9C695", + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF", ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, "Properties": Object { - "CloudWatchRoleArn": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { "Fn::GetAtt": Array [ - "testcloudfrontapigatewaylambdaLambdaRestApiCloudWatchRole7A327F48", + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF", "Arn", ], }, + "Runtime": "nodejs12.x", }, - "Type": "AWS::ApiGateway::Account", + "Type": "AWS::Lambda::Function", }, - "testcloudfrontapigatewaylambdaLambdaRestApiCloudWatchRole7A327F48": Object { + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -334,7 +247,14 @@ Object { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": Object { - "Service": "apigateway.amazonaws.com", + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", }, }, ], @@ -348,11 +268,7 @@ Object { "Action": Array [ "logs:CreateLogGroup", "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", ], "Effect": "Allow", "Resource": Object { @@ -367,7 +283,7 @@ Object { Object { "Ref": "AWS::AccountId", }, - ":*", + ":log-group:/aws/lambda/*", ], ], }, @@ -375,72 +291,157 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + "PolicyName": "LambdaFunctionServiceRolePolicy", }, ], }, "Type": "AWS::IAM::Role", }, - "testcloudfrontapigatewaylambdaRestApi96B9C695": Object { + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion1946ABC2": Object { "Properties": Object { - "EndpointConfiguration": Object { - "Types": Array [ - "REGIONAL", - ], + "FunctionName": Object { + "Ref": "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeaders6945414A", }, - "Name": "RestApi", }, - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::Lambda::Version", }, - "testcloudfrontapigatewaylambdaRestApiANY293F8177": Object { + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65": Object { + "DependsOn": Array [ + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, "Properties": Object { - "AuthorizationType": "AWS_IAM", - "HttpMethod": "ANY", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC", + }, + "S3Key": Object { "Fn::Join": Array [ "", Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", Object { - "Ref": "AWS::Region", + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872", + }, + ], + }, + ], }, - ":lambda:path/2015-03-31/functions/", Object { - "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", - "Arn", + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872", + }, + ], + }, ], }, - "/invocations", ], ], }, }, - "ResourceId": Object { + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + }, + }, + "Handler": "index.handler", + "Role": Object { "Fn::GetAtt": Array [ - "testcloudfrontapigatewaylambdaRestApi96B9C695", - "RootResourceId", + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F", + "Arn", ], }, - "RestApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44": Object { + "Properties": Object { + "EndpointConfiguration": Object { + "Types": Array [ + "REGIONAL", + ], }, + "Name": "LambdaRestApi", }, - "Type": "AWS::ApiGateway::Method", + "Type": "AWS::ApiGateway::RestApi", }, - "testcloudfrontapigatewaylambdaRestApiANYApiPermissionTesttestcloudfrontapigatewaylambdaRestApiB469ACF4ANY1049443E": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiANYApiPermissionTesttestcloudfrontapigatewaylambdaLambdaRestApi4FCEAD4FANY54D89D69": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn", ], }, @@ -463,7 +464,7 @@ Object { }, ":", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "/test-invoke-stage/*/", ], @@ -472,12 +473,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testcloudfrontapigatewaylambdaRestApiANYApiPermissiontestcloudfrontapigatewaylambdaRestApiB469ACF4ANY60888502": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiANYApiPermissiontestcloudfrontapigatewaylambdaLambdaRestApi4FCEAD4FANY575F6F0F": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn", ], }, @@ -500,11 +501,11 @@ Object { }, ":", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "/", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7", }, "/*/", ], @@ -513,11 +514,123 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testcloudfrontapigatewaylambdaRestApiDeployment3AAD18356ddf1e04746630aef78bc65a8edbab85": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiANYBC435DFD": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Fn::GetAtt": Array [ + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", + "RootResourceId", + ], + }, + "RestApiId": Object { + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, + "testcloudfrontapigatewaylambdaLambdaRestApiAccount1A4578BB": Object { + "DependsOn": Array [ + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "testcloudfrontapigatewaylambdaLambdaRestApiCloudWatchRole7A327F48", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "testcloudfrontapigatewaylambdaLambdaRestApiCloudWatchRole7A327F48": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testcloudfrontapigatewaylambdaLambdaRestApiDeployment0C4661C03abb023c303d9e3ff2b4d984cd5d60ab": Object { "DependsOn": Array [ - "testcloudfrontapigatewaylambdaRestApiproxyANY21F2417C", - "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30", - "testcloudfrontapigatewaylambdaRestApiANY293F8177", + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYAE500A13", + "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F", + "testcloudfrontapigatewaylambdaLambdaRestApiANYBC435DFD", ], "Metadata": Object { "cfn_nag": Object { @@ -532,12 +645,12 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { @@ -546,10 +659,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeployment3AAD18356ddf1e04746630aef78bc65a8edbab85", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeployment0C4661C03abb023c303d9e3ff2b4d984cd5d60ab", }, "MethodSettings": Array [ Object { @@ -560,21 +673,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "testcloudfrontapigatewaylambdaRestApiUsagePlan283916E7": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiUsagePlan59548A66": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "Stage": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7", }, "Throttle": Object {}, }, @@ -582,7 +695,7 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "testcloudfrontapigatewaylambdaRestApiproxyANY21F2417C": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYAE500A13": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -604,7 +717,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn", ], }, @@ -614,20 +727,20 @@ Object { }, }, "ResourceId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F", }, "RestApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, }, "Type": "AWS::ApiGateway::Method", }, - "testcloudfrontapigatewaylambdaRestApiproxyANYApiPermissionTesttestcloudfrontapigatewaylambdaRestApiB469ACF4ANYproxy3BCE2E38": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestcloudfrontapigatewaylambdaLambdaRestApi4FCEAD4FANYproxyDB9DBE95": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn", ], }, @@ -650,7 +763,7 @@ Object { }, ":", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "/test-invoke-stage/*/{proxy+}", ], @@ -659,12 +772,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testcloudfrontapigatewaylambdaRestApiproxyANYApiPermissiontestcloudfrontapigatewaylambdaRestApiB469ACF4ANYproxyA51D7C81": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestcloudfrontapigatewaylambdaLambdaRestApi4FCEAD4FANYproxy9F51CEF1": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn", ], }, @@ -687,11 +800,11 @@ Object { }, ":", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, "/", Object { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7", }, "/*/{proxy+}", ], @@ -700,17 +813,17 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30": Object { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F": Object { "Properties": Object { "ParentId": Object { "Fn::GetAtt": Array [ - "testcloudfrontapigatewaylambdaRestApi96B9C695", + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", "RootResourceId", ], }, "PathPart": "{proxy+}", "RestApiId": Object { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695", + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", }, }, "Type": "AWS::ApiGateway::Resource", diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.expected.json index e6f8073ec..28df3967d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.expected.json @@ -1,7 +1,132 @@ { "Description": "Integration Test for aws-cloudfront-apigateway-lambda", "Resources": { - "testcloudfrontapigatewaylambdaRestApi96B9C695": { + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" + } + } + }, + "DependsOn": [ + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testcloudfrontapigatewaylambdaApiAccessLogGroup97EB2E40": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -9,21 +134,21 @@ "REGIONAL" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "testcloudfrontapigatewaylambdaRestApiDeployment3AAD18356ddf1e04746630aef78bc65a8edbab85": { + "testcloudfrontapigatewaylambdaLambdaRestApiDeployment0C4661C03abb023c303d9e3ff2b4d984cd5d60ab": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "testcloudfrontapigatewaylambdaRestApiproxyANY21F2417C", - "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30", - "testcloudfrontapigatewaylambdaRestApiANY293F8177" + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYAE500A13", + "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F", + "testcloudfrontapigatewaylambdaLambdaRestApiANYBC435DFD" ], "Metadata": { "cfn_nag": { @@ -36,11 +161,11 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0": { + "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "AccessLogSetting": { "DestinationArn": { @@ -49,10 +174,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeployment3AAD18356ddf1e04746630aef78bc65a8edbab85" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeployment0C4661C03abb023c303d9e3ff2b4d984cd5d60ab" }, "MethodSettings": [ { @@ -65,28 +190,28 @@ "StageName": "prod" } }, - "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30": { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "testcloudfrontapigatewaylambdaRestApi96B9C695", + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" } } }, - "testcloudfrontapigatewaylambdaRestApiproxyANYApiPermissiontestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaRestApiEFF71B39ANYproxy384A83AC": { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaLambdaRestApi6591E8BAANYproxyE560AC8B": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -109,11 +234,11 @@ }, ":", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "/", { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7" }, "/*/{proxy+}" ] @@ -121,13 +246,13 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiproxyANYApiPermissionTesttestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaRestApiEFF71B39ANYproxy616372B7": { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaLambdaRestApi6591E8BAANYproxyB2A6E1F1": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -150,7 +275,7 @@ }, ":", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "/test-invoke-stage/*/{proxy+}" ] @@ -158,15 +283,15 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiproxyANY21F2417C": { + "testcloudfrontapigatewaylambdaLambdaRestApiproxyANYAE500A13": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "testcloudfrontapigatewaylambdaRestApiproxyBFEB2E30" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiproxyBC09D86F" }, "RestApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -187,7 +312,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -198,13 +323,13 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiANYApiPermissiontestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaRestApiEFF71B39ANY25A0D653": { + "testcloudfrontapigatewaylambdaLambdaRestApiANYApiPermissiontestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaLambdaRestApi6591E8BAANY0C6B5F8F": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -227,11 +352,11 @@ }, ":", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "/", { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7" }, "/*/" ] @@ -239,13 +364,13 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiANYApiPermissionTesttestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaRestApiEFF71B39ANYAEAD59C3": { + "testcloudfrontapigatewaylambdaLambdaRestApiANYApiPermissionTesttestcloudfrontapigatewaylambdastacktestcloudfrontapigatewaylambdaLambdaRestApi6591E8BAANY093347BF": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -268,7 +393,7 @@ }, ":", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "/test-invoke-stage/*/" ] @@ -276,18 +401,18 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiANY293F8177": { + "testcloudfrontapigatewaylambdaLambdaRestApiANYBC435DFD": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "testcloudfrontapigatewaylambdaRestApi96B9C695", + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44", "RootResourceId" ] }, "RestApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -308,7 +433,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcloudfrontapigatewaylambdaLambdaFunction17A55E65", "Arn" ] }, @@ -319,27 +444,22 @@ } } }, - "testcloudfrontapigatewaylambdaRestApiUsagePlan283916E7": { + "testcloudfrontapigatewaylambdaLambdaRestApiUsagePlan59548A66": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, "Stage": { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7" }, "Throttle": {} } ] } }, - "testcloudfrontapigatewaylambdaApiAccessLogGroup97EB2E40": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testcloudfrontapigatewaylambdaLambdaRestApiCloudWatchRole7A327F48": { "Type": "AWS::IAM::Role", "Properties": { @@ -406,9 +526,104 @@ } }, "DependsOn": [ - "testcloudfrontapigatewaylambdaRestApi96B9C695" + "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" ] }, + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeaders6945414A": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRoleCA39BFFF" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion1946ABC2": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeaders6945414A" + } + } + }, "testcloudfrontapigatewaylambdaCloudFrontToApiGatewayCloudfrontLoggingBucket7F467421": { "Type": "AWS::S3::Bucket", "Properties": { @@ -469,6 +684,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "testcloudfrontapigatewaylambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion1946ABC2" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -515,7 +738,7 @@ [ "https://", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, ".execute-api.", { @@ -527,7 +750,7 @@ }, "/", { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7" }, "/" ] @@ -549,123 +772,13 @@ "CloudFrontDefaultCertificate": true } } - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/lambda/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "LambdaFunctionServiceRolePolicy" - } - ] - } - }, - "LambdaFunctionBF21E41F": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "S3Bucket": { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC" - }, - "S3Key": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872" - } - ] - } - ] - } - ] - ] - } - }, - "Handler": "index.handler", - "Role": { - "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", - "Arn" - ] - }, - "Runtime": "nodejs10.x", - "Environment": { - "Variables": { - "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" - } - } }, - "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" - ], "Metadata": { "cfn_nag": { "rules_to_suppress": [ { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" } ] } @@ -673,14 +786,14 @@ } }, "Outputs": { - "testcloudfrontapigatewaylambdaRestApiEndpoint0A6CB43E": { + "testcloudfrontapigatewaylambdaLambdaRestApiEndpoint83FD8F0F": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "testcloudfrontapigatewaylambdaRestApi96B9C695" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApi6A4CBD44" }, ".execute-api.", { @@ -692,7 +805,7 @@ }, "/", { - "Ref": "testcloudfrontapigatewaylambdaRestApiDeploymentStageprod9373DCA0" + "Ref": "testcloudfrontapigatewaylambdaLambdaRestApiDeploymentStageprod4617A7B7" }, "/" ] diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts index d817775e5..c9185ae4d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts @@ -68,7 +68,7 @@ test('check lambda function properties for deploy: true', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testcloudfrontapigatewaylambdaLambdaFunctionServiceRoleCB74590F", "Arn" ] }, @@ -174,6 +174,6 @@ test('override api gateway properties', () => { "REGIONAL" ] }, - Name: "RestApi" + Name: "LambdaRestApi" }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/README.md b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/README.md index 1ad33c9c5..82ae9d7f1 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/README.md @@ -67,12 +67,12 @@ _Parameters_ |:-------------|:----------------|-----------------| |existingApiGatewayObj|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|The regional API Gateway that will be fronted with the CloudFront| |cloudFrontDistributionProps?|[`cloudfront.CloudFrontWebDistributionProps | any`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistributionProps.html)|Optional user provided props to override the default props for Cloudfront Distribution| - +|insertHttpSecurityHeaders?|`boolean`|Optional user provided props to turn on/off the automatic injection of best practice HTTP security headers in all resonses from cloudfront| ## Pattern Properties | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct| +|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct| |restApi()|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|Returns an instance of the API Gateway REST API created by the pattern.| ## Architecture diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/lib/index.ts index a781d7a94..06e7901ed 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/lib/index.ts @@ -25,13 +25,20 @@ export interface CloudFrontToApiGatewayProps { * * @default - None */ - readonly existingApiGatewayObj: api.RestApi + readonly existingApiGatewayObj: api.RestApi, /** * Optional user provided props to override the default props * * @default - Default props are used */ - readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any; + readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any, + /** + * Optional user provided props to turn on/off the automatic injection of best practice HTTP + * security headers in all resonses from cloudfront + * + * @default - true + */ + readonly insertHttpSecurityHeaders?: boolean; } export class CloudFrontToApiGateway extends Construct { @@ -52,11 +59,11 @@ export class CloudFrontToApiGateway extends Construct { this.api = props.existingApiGatewayObj; this.cloudfront = defaults.CloudFrontDistributionForApiGateway(this, props.existingApiGatewayObj, - props.cloudFrontDistributionProps); + props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); } /** - * @summary Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct. + * @summary Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct. * @returns {cloudfront.CloudFrontWebDistribution} Instance of CloudFrontWebDistribution created by the construct * @since 0.8.0 * @access public @@ -66,7 +73,7 @@ export class CloudFrontToApiGateway extends Construct { } /** - * @summary Retruns an instance of api.RestApi created by the construct. + * @summary Returns an instance of api.RestApi created by the construct. * @returns {api.RestApi} Instance of RestApi created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/package.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/package.json index c8072fafb..95cb9debf 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-cloudfront-apigateway", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Cloudfront to AWS API Gateway integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,16 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/__snapshots__/test.cloudfront-apigateway.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/__snapshots__/test.cloudfront-apigateway.test.js.snap index 73112c5a2..a1739d0ba 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/__snapshots__/test.cloudfront-apigateway.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/__snapshots__/test.cloudfront-apigateway.test.js.snap @@ -3,14 +3,14 @@ exports[`snapshot test CloudFrontToApiGateway default params 1`] = ` Object { "Outputs": Object { - "RestApiEndpoint0551178A": Object { + "LambdaRestApiEndpointCCECE4C1": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/", ], @@ -170,87 +170,18 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "RestApi0C43BF4B": Object { + "LambdaRestApi95870433": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "REGIONAL", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "LambdaRestApiANYA831AD87": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -283,17 +214,17 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "LambdaRestApi95870433", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionRestApiANY3A99B4EE": Object { + "LambdaRestApiANYApiPermissionLambdaRestApiANYD56C5914": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -321,11 +252,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/*/", ], @@ -334,7 +265,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestRestApiANY79BD91F2": Object { + "LambdaRestApiANYApiPermissionTestLambdaRestApiANY9B2403A7": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -362,7 +293,7 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/test-invoke-stage/*/", ], @@ -371,11 +302,80 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": Object { + "LambdaRestApiAccount": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", + "LambdaRestApi95870433", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "LambdaRestApiCloudWatchRoleF339D4E6", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "LambdaRestApiCloudWatchRoleF339D4E6": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7": Object { + "DependsOn": Array [ + "LambdaRestApiproxyANY93D43CC0", + "LambdaRestApiproxy9F99E187", + "LambdaRestApiANYA831AD87", ], "Metadata": Object { "cfn_nag": Object { @@ -390,12 +390,12 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "LambdaRestApiDeploymentStageprodB1F3862A": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { @@ -404,10 +404,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8", + "Ref": "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7", }, "MethodSettings": Array [ Object { @@ -418,21 +418,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiUsagePlan6E1C537A": Object { + "LambdaRestApiUsagePlanB4DF55D0": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "Throttle": Object {}, }, @@ -440,7 +440,22 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "LambdaRestApiproxy9F99E187": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "LambdaRestApi95870433", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "LambdaRestApi95870433", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "LambdaRestApiproxyANY93D43CC0": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -472,15 +487,15 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "LambdaRestApiproxy9F99E187", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionRestApiANYproxy9C9912F9": Object { + "LambdaRestApiproxyANYApiPermissionLambdaRestApiANYproxy208F31EB": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -508,11 +523,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/*/{proxy+}", ], @@ -521,7 +536,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestRestApiANYproxyCB7BC56D": Object { + "LambdaRestApiproxyANYApiPermissionTestLambdaRestApiANYproxyDBA3E731": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -549,7 +564,7 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/test-invoke-stage/*/{proxy+}", ], @@ -558,22 +573,17 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", + "testcloudfrontapigatewayCloudFrontDistributionCFDistribution2270C4C1": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, ], }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, }, - "Type": "AWS::ApiGateway::Resource", - }, - "testcloudfrontapigatewayCloudFrontDistributionCFDistribution2270C4C1": Object { "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -592,6 +602,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "testcloudfrontapigatewaySetHttpSecurityHeadersVersion7F8815E1", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -638,7 +656,7 @@ Object { Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, ".execute-api.", Object { @@ -650,7 +668,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/", ], @@ -715,6 +733,101 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, + "testcloudfrontapigatewaySetHttpSecurityHeadersD8DBA642": Object { + "DependsOn": Array [ + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testcloudfrontapigatewaySetHttpSecurityHeadersVersion7F8815E1": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "testcloudfrontapigatewaySetHttpSecurityHeadersD8DBA642", + }, + }, + "Type": "AWS::Lambda::Version", + }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/integ.no-arguments.expected.json index b6789edd2..1f4d0046f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/integ.no-arguments.expected.json @@ -121,7 +121,12 @@ } } }, - "RestApi0C43BF4B": { + "ApiAccessLogGroupCEA70788": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "LambdaRestApi95870433": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -129,21 +134,21 @@ "REGIONAL" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": { + "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94" + "LambdaRestApiproxyANY93D43CC0", + "LambdaRestApiproxy9F99E187", + "LambdaRestApiANYA831AD87" ], "Metadata": { "cfn_nag": { @@ -156,11 +161,11 @@ } } }, - "RestApiDeploymentStageprod3855DE66": { + "LambdaRestApiDeploymentStageprodB1F3862A": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "AccessLogSetting": { "DestinationArn": { @@ -169,10 +174,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8" + "Ref": "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7" }, "MethodSettings": [ { @@ -185,22 +190,22 @@ "StageName": "prod" } }, - "RestApiproxyC95856DD": { + "LambdaRestApiproxy9F99E187": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "LambdaRestApi95870433", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" } } }, - "RestApiproxyANYApiPermissiontestcloudfrontapigatewaystackRestApi3EC35350ANYproxy5C73D2AA": { + "LambdaRestApiproxyANYApiPermissiontestcloudfrontapigatewaystackLambdaRestApi5373EC8AANYproxyFC995DCC": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -229,11 +234,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A" }, "/*/{proxy+}" ] @@ -241,7 +246,7 @@ } } }, - "RestApiproxyANYApiPermissionTesttestcloudfrontapigatewaystackRestApi3EC35350ANYproxy2CC800FF": { + "LambdaRestApiproxyANYApiPermissionTesttestcloudfrontapigatewaystackLambdaRestApi5373EC8AANYproxy5F059360": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -270,7 +275,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "/test-invoke-stage/*/{proxy+}" ] @@ -278,15 +283,15 @@ } } }, - "RestApiproxyANY1786B242": { + "LambdaRestApiproxyANY93D43CC0": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "LambdaRestApiproxy9F99E187" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -318,7 +323,7 @@ } } }, - "RestApiANYApiPermissiontestcloudfrontapigatewaystackRestApi3EC35350ANYA1A8E51B": { + "LambdaRestApiANYApiPermissiontestcloudfrontapigatewaystackLambdaRestApi5373EC8AANY4A60D941": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -347,11 +352,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A" }, "/*/" ] @@ -359,7 +364,7 @@ } } }, - "RestApiANYApiPermissionTesttestcloudfrontapigatewaystackRestApi3EC35350ANYD4888E54": { + "LambdaRestApiANYApiPermissionTesttestcloudfrontapigatewaystackLambdaRestApi5373EC8AANY77697066": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -388,7 +393,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "/test-invoke-stage/*/" ] @@ -396,18 +401,18 @@ } } }, - "RestApiANYA7C1DC94": { + "LambdaRestApiANYA831AD87": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "LambdaRestApi95870433", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -439,27 +444,22 @@ } } }, - "RestApiUsagePlan6E1C537A": { + "LambdaRestApiUsagePlanB4DF55D0": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, "Stage": { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A" }, "Throttle": {} } ] } }, - "ApiAccessLogGroupCEA70788": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "LambdaRestApiCloudWatchRoleF339D4E6": { "Type": "AWS::IAM::Role", "Properties": { @@ -526,9 +526,104 @@ } }, "DependsOn": [ - "RestApi0C43BF4B" + "LambdaRestApi95870433" ] }, + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testcloudfrontapigatewaySetHttpSecurityHeadersD8DBA642": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "testcloudfrontapigatewaySetHttpSecurityHeadersServiceRole20BDDF39" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testcloudfrontapigatewaySetHttpSecurityHeadersVersion7F8815E1": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "testcloudfrontapigatewaySetHttpSecurityHeadersD8DBA642" + } + } + }, "testcloudfrontapigatewayCloudfrontLoggingBucket9811F6E8": { "Type": "AWS::S3::Bucket", "Properties": { @@ -589,6 +684,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "testcloudfrontapigatewaySetHttpSecurityHeadersVersion7F8815E1" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -635,7 +738,7 @@ [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, ".execute-api.", { @@ -647,7 +750,7 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A" }, "/" ] @@ -669,6 +772,16 @@ "CloudFrontDefaultCertificate": true } } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" + } + ] + } } } }, @@ -687,14 +800,14 @@ } }, "Outputs": { - "RestApiEndpoint0551178A": { + "LambdaRestApiEndpointCCECE4C1": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "LambdaRestApi95870433" }, ".execute-api.", { @@ -706,7 +819,7 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A" }, "/" ] diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts index 4f73c8375..15f8d4f6e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts @@ -74,7 +74,7 @@ test('test cloudfront DomainName', () => { [ "https://", { - Ref: "RestApi0C43BF4B" + Ref: "LambdaRestApi95870433" }, ".execute-api.", { @@ -86,7 +86,7 @@ test('test cloudfront DomainName', () => { }, "/", { - Ref: "RestApiDeploymentStageprod3855DE66" + Ref: "LambdaRestApiDeploymentStageprodB1F3862A" }, "/" ] diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/README.md b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/README.md index 81ef6f5a8..4a14b7186 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/README.md @@ -56,13 +56,14 @@ _Parameters_ |existingBucketObj?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Existing instance of S3 Bucket object| |bucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for S3 Bucket| |cloudFrontDistributionProps?|[`cloudfront.CloudFrontWebDistributionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistributionProps.html)|Optional user provided props to override the default props for Cloudfront Distribution| +|insertHttpSecurityHeaders?|`boolean`|Optional user provided props to turn on/off the automatic injection of best practice HTTP security headers in all resonses from cloudfront| ## Pattern Properties | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct| -|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Retruns an instance of s3.Bucket created by the construct| +|cloudFrontWebDistribution()|[`cloudfront.CloudFrontWebDistribution`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html)|Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct| +|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of s3.Bucket created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/lib/index.ts index 3c964398c..1732e7f07 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/lib/index.ts @@ -46,7 +46,14 @@ export interface CloudFrontToS3Props { * * @default - Default props are used */ - readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps; + readonly cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any, + /** + * Optional user provided props to turn on/off the automatic injection of best practice HTTP + * security headers in all resonses from cloudfront + * + * @default - true + */ + readonly insertHttpSecurityHeaders?: boolean; } export class CloudFrontToS3 extends Construct { @@ -70,11 +77,12 @@ export class CloudFrontToS3 extends Construct { bucketProps: props.bucketProps }); - this.cloudfront = defaults.CloudFrontDistributionForS3(this, this.s3Bucket, props.cloudFrontDistributionProps); + this.cloudfront = defaults.CloudFrontDistributionForS3(this, this.s3Bucket, + props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); } /** - * @summary Retruns an instance of cloudfront.CloudFrontWebDistribution created by the construct + * @summary Returns an instance of cloudfront.CloudFrontWebDistribution created by the construct * @returns {cloudfront.CloudFrontWebDistribution} Instance of CloudFrontWebDistribution created by the construct * @since 0.8.0 * @access public @@ -84,7 +92,7 @@ export class CloudFrontToS3 extends Construct { } /** - * @summary Retruns an instance of s3.Bucket created by the construct. + * @summary Returns an instance of s3.Bucket created by the construct. * @returns {s3.Bucket} Instance of Bucket created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/package.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/package.json index 1e93a17c8..943f0ab85 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-cloudfront-s3", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Cloudfront to AWS S3 integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,13 +53,14 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -69,9 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/__snapshots__/test.cloudfront-s3.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/__snapshots__/test.cloudfront-s3.test.js.snap index 8c8bbc06a..a3cd6c806 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/__snapshots__/test.cloudfront-s3.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/__snapshots__/test.cloudfront-s3.test.js.snap @@ -4,6 +4,16 @@ exports[`snapshot test CloudFrontToS3 default params 1`] = ` Object { "Resources": Object { "testcloudfronts3CloudFrontDistributionCFDistribution61FCC088": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -22,6 +32,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "testcloudfronts3SetHttpSecurityHeadersVersionF1C744BB", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -284,6 +302,101 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, + "testcloudfronts3SetHttpSecurityHeaders6C5A1E69": Object { + "DependsOn": Array [ + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testcloudfronts3SetHttpSecurityHeadersVersionF1C744BB": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "testcloudfronts3SetHttpSecurityHeaders6C5A1E69", + }, + }, + "Type": "AWS::Lambda::Version", + }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-arguments.expected.json index 98c1260e6..6abbb4f46 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-arguments.expected.json @@ -167,6 +167,109 @@ } } }, + "testcloudfronts3CloudFrontOriginAccessIdentity2C681839": { + "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", + "Properties": { + "CloudFrontOriginAccessIdentityConfig": { + "Comment": "Access S3 bucket content only through CloudFront" + } + } + }, + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testcloudfronts3SetHttpSecurityHeaders6C5A1E69": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "testcloudfronts3SetHttpSecurityHeadersServiceRole74D1E252" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testcloudfronts3SetHttpSecurityHeadersVersionF1C744BB": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "testcloudfronts3SetHttpSecurityHeaders6C5A1E69" + } + } + }, "testcloudfronts3CloudfrontLoggingBucket985C0FE8": { "Type": "AWS::S3::Bucket", "Properties": { @@ -207,14 +310,6 @@ } } }, - "testcloudfronts3CloudFrontOriginAccessIdentity2C681839": { - "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", - "Properties": { - "CloudFrontOriginAccessIdentityConfig": { - "Comment": "Access S3 bucket content only through CloudFront" - } - } - }, "testcloudfronts3CloudFrontDistributionCFDistribution61FCC088": { "Type": "AWS::CloudFront::Distribution", "Properties": { @@ -235,6 +330,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "testcloudfronts3SetHttpSecurityHeadersVersionF1C744BB" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -280,6 +383,16 @@ "CloudFrontDefaultCertificate": true } } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" + } + ] + } } } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.expected.json b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.expected.json new file mode 100644 index 000000000..3daaf5515 --- /dev/null +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.expected.json @@ -0,0 +1,296 @@ +{ + "Description": "Integration Test for aws-cloudfront-s3", + "Resources": { + "testcloudfronts3nosecurityheadersS3LoggingBucketF644B35F": { + "Type": "AWS::S3::Bucket", + "Properties": { + "AccessControl": "LogDeliveryWrite", + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W35", + "reason": "This S3 bucket is used as the access logging bucket for another bucket" + }, + { + "id": "W51", + "reason": "This S3 bucket Bucket does not need a bucket policy" + } + ] + } + } + }, + "testcloudfronts3nosecurityheadersS3Bucket4D06173D": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "LoggingConfiguration": { + "DestinationBucketName": { + "Ref": "testcloudfronts3nosecurityheadersS3LoggingBucketF644B35F" + } + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testcloudfronts3nosecurityheadersS3BucketPolicy99D27ED1": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "testcloudfronts3nosecurityheadersS3Bucket4D06173D" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::cloudfront:user/CloudFront Origin Access Identity ", + { + "Ref": "testcloudfronts3nosecurityheadersCloudFrontOriginAccessIdentity5321D214" + } + ] + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersS3Bucket4D06173D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersS3Bucket4D06173D", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "s3:GetObject", + "Effect": "Allow", + "Principal": { + "CanonicalUser": { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersCloudFrontOriginAccessIdentity5321D214", + "S3CanonicalUserId" + ] + } + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersS3Bucket4D06173D", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "F16", + "reason": "Public website bucket policy requires a wildcard principal" + } + ] + } + } + }, + "testcloudfronts3nosecurityheadersCloudFrontOriginAccessIdentity5321D214": { + "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", + "Properties": { + "CloudFrontOriginAccessIdentityConfig": { + "Comment": "Access S3 bucket content only through CloudFront" + } + } + }, + "testcloudfronts3nosecurityheadersCloudfrontLoggingBucket92A5E2A5": { + "Type": "AWS::S3::Bucket", + "Properties": { + "AccessControl": "LogDeliveryWrite", + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W35", + "reason": "This S3 bucket is used as the access logging bucket for CloudFront Distribution" + }, + { + "id": "W51", + "reason": "This S3 bucket is used as the access logging bucket for CloudFront Distribution" + } + ] + } + } + }, + "testcloudfronts3nosecurityheadersCloudFrontDistributionCFDistribution3F3C52A8": { + "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, + "Logging": { + "Bucket": { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersCloudfrontLoggingBucket92A5E2A5", + "RegionalDomainName" + ] + }, + "IncludeCookies": false + }, + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "testcloudfronts3nosecurityheadersS3Bucket4D06173D", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "S3OriginConfig": { + "OriginAccessIdentity": { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + "Ref": "testcloudfronts3nosecurityheadersCloudFrontOriginAccessIdentity5321D214" + } + ] + ] + } + } + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.ts new file mode 100644 index 000000000..707be99ee --- /dev/null +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/integ.no-security-headers.ts @@ -0,0 +1,32 @@ +/** + * Copyright 2019 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. + */ + +// Imports +import { App, Stack } from "@aws-cdk/core"; +import { CloudFrontToS3, CloudFrontToS3Props } from "../lib"; + +// Setup +const app = new App(); +const stack = new Stack(app, 'test-cloudfront-s3-no-security-headers'); +stack.templateOptions.description = 'Integration Test for aws-cloudfront-s3'; + +// Definitions +const props: CloudFrontToS3Props = { + deployBucket: true, + insertHttpSecurityHeaders: false +}; + +new CloudFrontToS3(stack, 'test-cloudfront-s3-no-security-headers', props); + +// Synth +app.synth(); diff --git a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts index cc86d6f86..23098e514 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cloudfront-s3/test/test.cloudfront-s3.test.ts @@ -105,6 +105,99 @@ test('check existing bucket', () => { }); +test('test cloudfront with custom domain names', () => { + const stack = new cdk.Stack(); + + const props: CloudFrontToS3Props = { + deployBucket: true, + cloudFrontDistributionProps: { + aliasConfiguration: { + acmCertRef: '/acm/mycertificate', + names: ['mydomains'] + } + } + }; + + new CloudFrontToS3(stack, 'test-cloudfront-s3', props); + + expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { + DistributionConfig: { + Aliases: [ + "mydomains" + ], + DefaultCacheBehavior: { + AllowedMethods: [ + "GET", + "HEAD" + ], + CachedMethods: [ + "GET", + "HEAD" + ], + Compress: true, + ForwardedValues: { + Cookies: { + Forward: "none" + }, + QueryString: false + }, + LambdaFunctionAssociations: [ + { + EventType: "origin-response", + LambdaFunctionARN: { + Ref: "testcloudfronts3SetHttpSecurityHeadersVersionF1C744BB" + } + } + ], + TargetOriginId: "origin1", + ViewerProtocolPolicy: "redirect-to-https" + }, + DefaultRootObject: "index.html", + Enabled: true, + HttpVersion: "http2", + IPV6Enabled: true, + Logging: { + Bucket: { + "Fn::GetAtt": [ + "testcloudfronts3CloudfrontLoggingBucket985C0FE8", + "RegionalDomainName" + ] + }, + IncludeCookies: false + }, + Origins: [ + { + DomainName: { + "Fn::GetAtt": [ + "testcloudfronts3S3BucketE0C5F76E", + "RegionalDomainName" + ] + }, + Id: "origin1", + S3OriginConfig: { + OriginAccessIdentity: { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + Ref: "testcloudfronts3CloudFrontOriginAccessIdentity2C681839" + } + ] + ] + } + } + } + ], + PriceClass: "PriceClass_100", + ViewerCertificate: { + AcmCertificateArn: "/acm/mycertificate", + SslSupportMethod: "sni-only" + } + } + }); +}); + test('check exception for Missing existingObj from props for deploy = false', () => { const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/README.md index d74bb723a..2b139ac10 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/README.md @@ -71,10 +71,10 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|restApi()|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|Retruns an instance of api.RestApi created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| -|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Retruns an instance of cognito.UserPool created by the construct| -|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Retruns an instance of cognito.UserPoolClient created by the construct| +|restApi()|[`api.RestApi`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html)|Returns an instance of api.RestApi created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| +|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Returns an instance of cognito.UserPool created by the construct| +|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Returns an instance of cognito.UserPoolClient created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/lib/index.ts index 4d0569169..8e59fadaf 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/lib/index.ts @@ -79,16 +79,16 @@ export class CognitoToApiGatewayToLambda extends Construct { constructor(scope: Construct, id: string, props: CognitoToApiGatewayToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps }); - this.api = defaults.GlobalLambdaRestApi(scope, this.fn, props.apiGatewayProps); - this.userpool = defaults.buildUserPool(scope, props.cognitoUserPoolProps); - this.userpoolclient = defaults.buildUserPoolClient(scope, this.userpool, props.cognitoUserPoolClientProps); + this.api = defaults.GlobalLambdaRestApi(this, this.fn, props.apiGatewayProps); + this.userpool = defaults.buildUserPool(this, props.cognitoUserPoolProps); + this.userpoolclient = defaults.buildUserPoolClient(this, this.userpool, props.cognitoUserPoolClientProps); - const cfnAuthorizer = new api.CfnAuthorizer(scope, 'CognitoAuthorizer', { + const cfnAuthorizer = new api.CfnAuthorizer(this, 'CognitoAuthorizer', { restApiId: this.api.restApiId, type: 'COGNITO_USER_POOLS', providerArns: [this.userpool.userPoolArn], @@ -109,7 +109,7 @@ export class CognitoToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of api.RestApi created by the construct. + * @summary Returns an instance of api.RestApi created by the construct. * @returns {api.RestApi} Instance of RestApi created by the construct * @since 0.8.0 * @access public @@ -119,7 +119,7 @@ export class CognitoToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of Function created by the construct * @since 0.8.0 * @access public @@ -129,7 +129,7 @@ export class CognitoToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of cognito.UserPool created by the construct. + * @summary Returns an instance of cognito.UserPool created by the construct. * @returns {cognito.UserPool} Instance of UserPool created by the construct * @since 0.8.0 * @access public @@ -139,7 +139,7 @@ export class CognitoToApiGatewayToLambda extends Construct { } /** - * @summary Retruns an instance of cognito.UserPoolClient created by the construct. + * @summary Returns an instance of cognito.UserPoolClient created by the construct. * @returns {cognito.UserPoolClient} Instance of UserPoolClient created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/package.json index fae825011..0ea892116 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-cognito-apigateway-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Cognito to AWS API Gateway to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/__snapshots__/test.cognito-apigateway-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/__snapshots__/test.cognito-apigateway-lambda.test.js.snap index 8ca2165cf..12f9d5f05 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/__snapshots__/test.cognito-apigateway-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/__snapshots__/test.cognito-apigateway-lambda.test.js.snap @@ -3,14 +3,14 @@ exports[`snapshot test CognitoToApiGatewayToLambda default params 1`] = ` Object { "Outputs": Object { - "RestApiEndpoint0551178A": Object { + "testcognitoapigatewaylambdaLambdaRestApiEndpointBF0175D7": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1", }, "/", ], @@ -45,50 +45,117 @@ Object { }, }, "Resources": Object { - "ApiAccessLogGroupCEA70788": Object { + "testcognitoapigatewaylambdaApiAccessLogGroup9D0D0917": Object { "DeletionPolicy": "Retain", "Type": "AWS::Logs::LogGroup", "UpdateReplacePolicy": "Retain", }, - "CognitoAuthorizer": Object { + "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9": Object { "Properties": Object { "IdentitySource": "method.request.header.Authorization", "Name": "authorizer", "ProviderARNs": Array [ Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "testcognitoapigatewaylambdaCognitoUserPoolD5E74489", "Arn", ], }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, "Type": "COGNITO_USER_POOLS", }, "Type": "AWS::ApiGateway::Authorizer", }, - "CognitoUserPool53E37E69": Object { + "testcognitoapigatewaylambdaCognitoUserPoolClientDA118627": Object { "Properties": Object { - "LambdaConfig": Object {}, + "UserPoolId": Object { + "Ref": "testcognitoapigatewaylambdaCognitoUserPoolD5E74489", + }, + }, + "Type": "AWS::Cognito::UserPoolClient", + }, + "testcognitoapigatewaylambdaCognitoUserPoolD5E74489": Object { + "Properties": Object { + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "testcognitoapigatewaylambdaCognitoUserPoolF2D785A1", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "testcognitoapigatewaylambdaCognitoUserPoolsmsRoleB297EE96", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, - "CognitoUserPoolClient5AB59AE4": Object { + "testcognitoapigatewaylambdaCognitoUserPoolsmsRoleB297EE96": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], + }, + }, "Properties": Object { - "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "testcognitoapigatewaylambdaCognitoUserPoolF2D785A1", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", + }, + ], }, - "Type": "AWS::Cognito::UserPoolClient", + "Type": "AWS::IAM::Role", }, - "LambdaFunctionBF21E41F": Object { + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510", ], "Metadata": Object { "cfn_nag": Object { @@ -147,7 +214,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510", "Arn", ], }, @@ -155,7 +222,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -206,91 +273,22 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "RestApi0C43BF4B": Object { + "testcognitoapigatewaylambdaLambdaRestApi2E272431": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "EDGE", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "testcognitoapigatewaylambdaLambdaRestApiANY1BCFE40A": Object { "Properties": Object { "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": Object { - "Ref": "CognitoAuthorizer", + "Ref": "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9", }, "HttpMethod": "ANY", "Integration": Object { @@ -311,7 +309,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -322,22 +320,22 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "testcognitoapigatewaylambdaLambdaRestApi2E272431", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionRestApiANY3A99B4EE": Object { + "testcognitoapigatewaylambdaLambdaRestApiANYApiPermissionTesttestcognitoapigatewaylambdaLambdaRestApi7DADE73DANY38E57350": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -360,25 +358,21 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, - "/*/", + "/test-invoke-stage/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestRestApiANY79BD91F2": Object { + "testcognitoapigatewaylambdaLambdaRestApiANYApiPermissiontestcognitoapigatewaylambdaLambdaRestApi7DADE73DANYCE72E572": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -401,20 +395,93 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, - "/test-invoke-stage/*/", + "/", + Object { + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1", + }, + "/*/", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": Object { + "testcognitoapigatewaylambdaLambdaRestApiAccountD303BB82": Object { + "DependsOn": Array [ + "testcognitoapigatewaylambdaLambdaRestApi2E272431", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "testcognitoapigatewaylambdaLambdaRestApiCloudWatchRole0AC7FF3B", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "testcognitoapigatewaylambdaLambdaRestApiCloudWatchRole0AC7FF3B": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testcognitoapigatewaylambdaLambdaRestApiDeployment96AFD8CA5d8e3257747e529ac6f9e48e8d20548e": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", + "testcognitoapigatewaylambdaLambdaRestApiproxyANY18BA6246", + "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20", + "testcognitoapigatewaylambdaLambdaRestApiANY1BCFE40A", ], "Metadata": Object { "cfn_nag": Object { @@ -429,24 +496,24 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { "Fn::GetAtt": Array [ - "ApiAccessLogGroupCEA70788", + "testcognitoapigatewaylambdaApiAccessLogGroup9D0D0917", "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8", + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeployment96AFD8CA5d8e3257747e529ac6f9e48e8d20548e", }, "MethodSettings": Array [ Object { @@ -457,21 +524,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiUsagePlan6E1C537A": Object { + "testcognitoapigatewaylambdaLambdaRestApiUsagePlan75371896": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1", }, "Throttle": Object {}, }, @@ -479,11 +546,26 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "testcognitoapigatewaylambdaLambdaRestApi2E272431", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "testcognitoapigatewaylambdaLambdaRestApiproxyANY18BA6246": Object { "Properties": Object { "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": Object { - "Ref": "CognitoAuthorizer", + "Ref": "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9", }, "HttpMethod": "ANY", "Integration": Object { @@ -504,7 +586,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -514,20 +596,20 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionRestApiANYproxy9C9912F9": Object { + "testcognitoapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestcognitoapigatewaylambdaLambdaRestApi7DADE73DANYproxyE7ABD170": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -550,25 +632,21 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, - "/*/{proxy+}", + "/test-invoke-stage/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestRestApiANYproxyCB7BC56D": Object { + "testcognitoapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestcognitoapigatewaylambdaLambdaRestApi7DADE73DANYproxyE8E57826": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn", ], }, @@ -591,30 +669,19 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431", }, - "/test-invoke-stage/*/{proxy+}", + "/", + Object { + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1", + }, + "/*/{proxy+}", ], ], }, }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/integ.no-arguments.expected.json index a66b08eae..3109add75 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/integ.no-arguments.expected.json @@ -1,6 +1,6 @@ { "Resources": { - "LambdaFunctionServiceRole0C4CDE0B": { + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -51,7 +51,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -95,7 +95,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510", "Arn" ] }, @@ -107,7 +107,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testcognitoapigatewaylambdaLambdaFunctionServiceRole943D8510" ], "Metadata": { "cfn_nag": { @@ -120,7 +120,12 @@ } } }, - "RestApi0C43BF4B": { + "testcognitoapigatewaylambdaApiAccessLogGroup9D0D0917": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testcognitoapigatewaylambdaLambdaRestApi2E272431": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -128,21 +133,21 @@ "EDGE" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": { + "testcognitoapigatewaylambdaLambdaRestApiDeployment96AFD8CA5d8e3257747e529ac6f9e48e8d20548e": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94" + "testcognitoapigatewaylambdaLambdaRestApiproxyANY18BA6246", + "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20", + "testcognitoapigatewaylambdaLambdaRestApiANY1BCFE40A" ], "Metadata": { "cfn_nag": { @@ -155,23 +160,23 @@ } } }, - "RestApiDeploymentStageprod3855DE66": { + "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "AccessLogSetting": { "DestinationArn": { "Fn::GetAtt": [ - "ApiAccessLogGroupCEA70788", + "testcognitoapigatewaylambdaApiAccessLogGroup9D0D0917", "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeployment96AFD8CA5d8e3257747e529ac6f9e48e8d20548e" }, "MethodSettings": [ { @@ -184,28 +189,28 @@ "StageName": "prod" } }, - "RestApiproxyC95856DD": { + "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testcognitoapigatewaylambdaLambdaRestApi2E272431", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" } } }, - "RestApiproxyANYApiPermissiontestcognitoapigatewaylambdastackRestApi7173ADDDANYproxyEE672F74": { + "testcognitoapigatewaylambdaLambdaRestApiproxyANYApiPermissiontestcognitoapigatewaylambdastacktestcognitoapigatewaylambdaLambdaRestApi8EF2D7DFANYproxyFA68200B": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -228,11 +233,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1" }, "/*/{proxy+}" ] @@ -240,13 +245,13 @@ } } }, - "RestApiproxyANYApiPermissionTesttestcognitoapigatewaylambdastackRestApi7173ADDDANYproxyF4659A23": { + "testcognitoapigatewaylambdaLambdaRestApiproxyANYApiPermissionTesttestcognitoapigatewaylambdastacktestcognitoapigatewaylambdaLambdaRestApi8EF2D7DFANYproxy5FDD10FD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -269,7 +274,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "/test-invoke-stage/*/{proxy+}" ] @@ -277,19 +282,19 @@ } } }, - "RestApiproxyANY1786B242": { + "testcognitoapigatewaylambdaLambdaRestApiproxyANY18BA6246": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiproxy23E1DA20" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": { - "Ref": "CognitoAuthorizer" + "Ref": "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9" }, "Integration": { "IntegrationHttpMethod": "POST", @@ -309,7 +314,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -320,13 +325,13 @@ } } }, - "RestApiANYApiPermissiontestcognitoapigatewaylambdastackRestApi7173ADDDANY5461DBBA": { + "testcognitoapigatewaylambdaLambdaRestApiANYApiPermissiontestcognitoapigatewaylambdastacktestcognitoapigatewaylambdaLambdaRestApi8EF2D7DFANY4E92AE99": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -349,11 +354,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1" }, "/*/" ] @@ -361,13 +366,13 @@ } } }, - "RestApiANYApiPermissionTesttestcognitoapigatewaylambdastackRestApi7173ADDDANYB2D94B09": { + "testcognitoapigatewaylambdaLambdaRestApiANYApiPermissionTesttestcognitoapigatewaylambdastacktestcognitoapigatewaylambdaLambdaRestApi8EF2D7DFANYDB98EE4F": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -390,7 +395,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "/test-invoke-stage/*/" ] @@ -398,22 +403,22 @@ } } }, - "RestApiANYA7C1DC94": { + "testcognitoapigatewaylambdaLambdaRestApiANY1BCFE40A": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "testcognitoapigatewaylambdaLambdaRestApi2E272431", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": { - "Ref": "CognitoAuthorizer" + "Ref": "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9" }, "Integration": { "IntegrationHttpMethod": "POST", @@ -433,7 +438,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testcognitoapigatewaylambdaLambdaFunction0C8EAC23", "Arn" ] }, @@ -444,28 +449,23 @@ } } }, - "RestApiUsagePlan6E1C537A": { + "testcognitoapigatewaylambdaLambdaRestApiUsagePlan75371896": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "Stage": { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1" }, "Throttle": {} } ] } }, - "ApiAccessLogGroupCEA70788": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaRestApiCloudWatchRoleF339D4E6": { + "testcognitoapigatewaylambdaLambdaRestApiCloudWatchRole0AC7FF3B": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -520,42 +520,109 @@ ] } }, - "LambdaRestApiAccount": { + "testcognitoapigatewaylambdaLambdaRestApiAccountD303BB82": { "Type": "AWS::ApiGateway::Account", "Properties": { "CloudWatchRoleArn": { "Fn::GetAtt": [ - "LambdaRestApiCloudWatchRoleF339D4E6", + "testcognitoapigatewaylambdaLambdaRestApiCloudWatchRole0AC7FF3B", "Arn" ] } }, "DependsOn": [ - "RestApi0C43BF4B" + "testcognitoapigatewaylambdaLambdaRestApi2E272431" ] }, - "CognitoUserPool53E37E69": { + "testcognitoapigatewaylambdaCognitoUserPoolsmsRoleB297EE96": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "testcognitoapigatewaylambdastacktestcognitoapigatewaylambdaCognitoUserPool2F1A43CB" + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cognito-idp.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "sns-publish" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish" + } + ] + } + } + }, + "testcognitoapigatewaylambdaCognitoUserPoolD5E74489": { "Type": "AWS::Cognito::UserPool", "Properties": { - "LambdaConfig": {}, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": { + "ExternalId": "testcognitoapigatewaylambdastacktestcognitoapigatewaylambdaCognitoUserPool2F1A43CB", + "SnsCallerArn": { + "Fn::GetAtt": [ + "testcognitoapigatewaylambdaCognitoUserPoolsmsRoleB297EE96", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": { "AdvancedSecurityMode": "ENFORCED" + }, + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}" } } }, - "CognitoUserPoolClient5AB59AE4": { + "testcognitoapigatewaylambdaCognitoUserPoolClientDA118627": { "Type": "AWS::Cognito::UserPoolClient", "Properties": { "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testcognitoapigatewaylambdaCognitoUserPoolD5E74489" } } }, - "CognitoAuthorizer": { + "testcognitoapigatewaylambdaCognitoAuthorizer170CACC9": { "Type": "AWS::ApiGateway::Authorizer", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, "Type": "COGNITO_USER_POOLS", "IdentitySource": "method.request.header.Authorization", @@ -563,7 +630,7 @@ "ProviderARNs": [ { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "testcognitoapigatewaylambdaCognitoUserPoolD5E74489", "Arn" ] } @@ -571,29 +638,15 @@ } } }, - "Parameters": { - "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC": { - "Type": "String", - "Description": "S3 bucket for asset \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" - }, - "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872": { - "Type": "String", - "Description": "S3 key for asset version \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" - }, - "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cArtifactHash00A70A91": { - "Type": "String", - "Description": "Artifact hash for asset \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" - } - }, "Outputs": { - "RestApiEndpoint0551178A": { + "testcognitoapigatewaylambdaLambdaRestApiEndpointBF0175D7": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "testcognitoapigatewaylambdaLambdaRestApi2E272431" }, ".execute-api.", { @@ -605,12 +658,26 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "testcognitoapigatewaylambdaLambdaRestApiDeploymentStageprod850C17D1" }, "/" ] ] } } + }, + "Parameters": { + "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3Bucket1F467BCC": { + "Type": "String", + "Description": "S3 bucket for asset \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" + }, + "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cS3VersionKey9E4F7872": { + "Type": "String", + "Description": "S3 key for asset version \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" + }, + "AssetParameters42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198cArtifactHash00A70A91": { + "Type": "String", + "Description": "Artifact hash for asset \"42a35bbf0dec9ef0ac5b0dde87e71a1b8929e8d2d178dd09ccfb2c928ec0198c\"" + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts index 6beea624a..2eefc1f17 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts @@ -48,7 +48,7 @@ test('override cognito properties', () => { const cognitoUserPoolProps: cognito.UserPoolProps = { userPoolName: 'test', - autoVerifiedAttributes: [cognito.UserPoolAttribute.EMAIL] + userVerification: {} }; new CognitoToApiGatewayToLambda(stack, 'test-cognito-apigateway-lambda', { @@ -59,14 +59,31 @@ test('override cognito properties', () => { expect(stack).toHaveResource('AWS::Cognito::UserPool', { - AutoVerifiedAttributes: [ - "email" - ], - LambdaConfig: {}, + AdminCreateUserConfig: { + AllowAdminCreateUserOnly: true + }, + EmailVerificationMessage: "The verification code to your new account is {####}", + EmailVerificationSubject: "Verify your new account", + SmsConfiguration: { + ExternalId: "testcognitoapigatewaylambdaCognitoUserPoolF2D785A1", + SnsCallerArn: { + "Fn::GetAtt": [ + "testcognitoapigatewaylambdaCognitoUserPoolsmsRoleB297EE96", + "Arn" + ] + } + }, + SmsVerificationMessage: "The verification code to your new account is {####}", UserPoolAddOns: { AdvancedSecurityMode: "ENFORCED" }, - UserPoolName: "test" + UserPoolName: "test", + VerificationMessageTemplate: { + DefaultEmailOption: "CONFIRM_WITH_CODE", + EmailMessage: "The verification code to your new account is {####}", + EmailSubject: "Verify your new account", + SmsMessage: "The verification code to your new account is {####}" + } }); }); diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md index 4168da891..09da02fd5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md @@ -71,13 +71,13 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Retruns an instance of dynamodb.Table created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| -|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Retruns an instance of cognito.UserPool created by the construct| -|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Retruns an instance of cognito.UserPoolClient created by the construct| -|identityPool()|[`cognito.CfnIdentityPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.CfnIdentityPool.html)|Retruns an instance of cognito.CfnIdentityPool created by the construct| -|elasticsearchDomain()|[`elasticsearch.CfnDomain`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticsearch.CfnDomain.html)|Retruns an instance of elasticsearch.CfnDomain created by the construct| -|cloudwatchAlarms()|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Retruns a list of cloudwatch.Alarm created by the construct| +|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Returns an instance of dynamodb.Table created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| +|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Returns an instance of cognito.UserPool created by the construct| +|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Returns an instance of cognito.UserPoolClient created by the construct| +|identityPool()|[`cognito.CfnIdentityPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.CfnIdentityPool.html)|Returns an instance of cognito.CfnIdentityPool created by the construct| +|elasticsearchDomain()|[`elasticsearch.CfnDomain`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticsearch.CfnDomain.html)|Returns an instance of elasticsearch.CfnDomain created by the construct| +|cloudwatchAlarms()|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of cloudwatch.Alarm created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/lib/index.ts index 513a57dd4..65fb464d0 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/lib/index.ts @@ -96,7 +96,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { dynamoTableProps: props.dynamoTableProps }; - this.dynamoDBStreamToLambda = new DynamoDBStreamToLambda(scope, 'DynamoDBStreamToLambda', _props1); + this.dynamoDBStreamToLambda = new DynamoDBStreamToLambda(this, 'DynamoDBStreamToLambda', _props1); this.fn = this.dynamoDBStreamToLambda.lambdaFunction(); @@ -107,11 +107,11 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { esDomainProps: props.esDomainProps }; - this.lambdaToElasticSearchAndKibana = new LambdaToElasticSearchAndKibana(scope, 'LambdaToElasticSearch', _props2); + this.lambdaToElasticSearchAndKibana = new LambdaToElasticSearchAndKibana(this, 'LambdaToElasticSearch', _props2); } /** - * @summary Retruns an instance of dynamodb.Table created by the construct. + * @summary Returns an instance of dynamodb.Table created by the construct. * @returns {dynamodb.Table} Instance of dynamodb.Table created by the construct * @since 0.8.0 * @access public @@ -121,7 +121,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public @@ -131,7 +131,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.UserPool created by the construct. + * @summary Returns an instance of cognito.UserPool created by the construct. * @returns {cognito.UserPool} Instance of UserPool created by the construct * @since 0.8.0 * @access public @@ -141,7 +141,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.UserPoolClient created by the construct. + * @summary Returns an instance of cognito.UserPoolClient created by the construct. * @returns {cognito.UserPoolClient} Instance of UserPoolClient created by the construct * @since 0.8.0 * @access public @@ -151,7 +151,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.CfnIdentityPool created by the construct. + * @summary Returns an instance of cognito.CfnIdentityPool created by the construct. * @returns {cognito.CfnIdentityPool} Instance of CfnIdentityPool created by the construct * @since 0.8.0 * @access public @@ -161,7 +161,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of elasticsearch.CfnDomain created by the construct. + * @summary Returns an instance of elasticsearch.CfnDomain created by the construct. * @returns {elasticsearch.CfnDomain} Instance of CfnDomain created by the construct * @since 0.8.0 * @access public @@ -171,7 +171,7 @@ export class DynamoDBStreamToLambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns a list of cloudwatch.Alarm created by the construct. + * @summary Returns a list of cloudwatch.Alarm created by the construct. * @returns {cloudwatch.Alarm[]} List of cloudwatch.Alarm created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json index acdb920fd..b7a1a5fa3 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for Amazon Dynamodb stream to AWS Lambda to AWS Elasticsearch with Kibana integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,19 +53,20 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-dynamodb-stream-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-dynamodb-stream-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -75,15 +76,16 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-dynamodb-stream-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana": "~0.8.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-dynamodb-stream-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana": "~0.8.1", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/__snapshots__/dynamodb-stream-lambda-elasticsearch-kibana.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/__snapshots__/dynamodb-stream-lambda-elasticsearch-kibana.test.js.snap index 4d657e049..2679dfe89 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/__snapshots__/dynamodb-stream-lambda-elasticsearch-kibana.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/__snapshots__/dynamodb-stream-lambda-elasticsearch-kibana.test.js.snap @@ -17,7 +17,224 @@ Object { }, }, "Resources": Object { - "AutomatedSnapshotFailureTooHighAlarmA7918D4F": Object { + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaDynamoTable9A779B83": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "AttributeDefinitions": Array [ + Object { + "AttributeName": "id", + "AttributeType": "S", + }, + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": Array [ + Object { + "AttributeName": "id", + "KeyType": "HASH", + }, + ], + "SSESpecification": Object { + "SSEEnabled": true, + }, + "StreamSpecification": Object { + "StreamViewType": "NEW_AND_OLD_IMAGES", + }, + }, + "Type": "AWS::DynamoDB::Table", + "UpdateReplacePolicy": "Retain", + }, + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunction10347BD5": Object { + "DependsOn": Array [ + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicyF8F69900", + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleB674EE63", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3Bucket87AE2D86", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3VersionKey6EF53907", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3VersionKey6EF53907", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "DOMAIN_ENDPOINT": Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchElasticsearchDomainD539E435", + "DomainEndpoint", + ], + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleB674EE63", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionDynamoDBEventSourcetestdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaDynamoTable0DD1CCDAA02C0130": Object { + "Properties": Object { + "BatchSize": 100, + "EventSourceArn": Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaDynamoTable9A779B83", + "StreamArn", + ], + }, + "FunctionName": Object { + "Ref": "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunction10347BD5", + }, + "StartingPosition": "TRIM_HORIZON", + }, + "Type": "AWS::Lambda::EventSourceMapping", + }, + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleB674EE63": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicyF8F69900": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "dynamodb:ListStreams", + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaDynamoTable9A779B83", + "Arn", + ], + }, + "/stream/*", + ], + ], + }, + }, + Object { + "Action": Array [ + "dynamodb:DescribeStream", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaDynamoTable9A779B83", + "StreamArn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicyF8F69900", + "Roles": Array [ + Object { + "Ref": "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleB674EE63", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchAutomatedSnapshotFailureTooHighAlarm79E9F162": Object { "Properties": Object { "AlarmDescription": "An automated snapshot failed. This failure is often the result of a red cluster health status.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -30,7 +247,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "CPUUtilizationTooHighAlarmA395C469": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCPUUtilizationTooHighAlarmFA0BD382": Object { "Properties": Object { "AlarmDescription": "100% CPU utilization is not uncommon, but sustained high usage is problematic. Consider using larger instance types or adding instances.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -43,7 +260,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "CognitoAuthorizedRole14E74FE0": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoAuthorizedRole4B91C04E": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -55,7 +272,7 @@ Object { }, "StringEquals": Object { "cognito-identity.amazonaws.com:aud": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoIdentityPool68C76F43", }, }, }, @@ -100,17 +317,17 @@ Object { }, "Type": "AWS::IAM::Role", }, - "CognitoIdentityPool": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoIdentityPool68C76F43": Object { "Properties": Object { "AllowUnauthenticatedIdentities": false, "CognitoIdentityProviders": Array [ Object { "ClientId": Object { - "Ref": "CognitoUserPoolClient5AB59AE4", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolClientE03C5E18", }, "ProviderName": Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", "ProviderName", ], }, @@ -120,7 +337,7 @@ Object { }, "Type": "AWS::Cognito::IdentityPool", }, - "CognitoKibanaConfigureRole62CCE76A": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRoleC8DCD692": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -137,7 +354,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "CognitoKibanaConfigureRolePolicy76F46A5E": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRolePolicy96BB58EC": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -160,7 +377,7 @@ Object { "Resource": Array [ Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", "Arn", ], }, @@ -178,7 +395,7 @@ Object { }, ":identitypool/", Object { - "Ref": "CognitoIdentityPool", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoIdentityPool68C76F43", }, ], ], @@ -211,7 +428,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "CognitoKibanaConfigureRole62CCE76A", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRoleC8DCD692", "Arn", ], }, @@ -219,59 +436,100 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "CognitoKibanaConfigureRolePolicy76F46A5E", + "PolicyName": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRolePolicy96BB58EC", "Roles": Array [ Object { - "Ref": "CognitoKibanaConfigureRole62CCE76A", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRoleC8DCD692", }, ], }, "Type": "AWS::IAM::Policy", }, - "CognitoUserPool53E37E69": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolClientE03C5E18": Object { + "Properties": Object { + "UserPoolId": Object { + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", + }, + }, + "Type": "AWS::Cognito::UserPoolClient", + }, + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5": Object { "Properties": Object { - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPool7B7B74A9", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolsmsRole58D31AFA", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, - "CognitoUserPoolClient5AB59AE4": Object { - "Properties": Object { - "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolsmsRole58D31AFA": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], }, }, - "Type": "AWS::Cognito::UserPoolClient", - }, - "DynamoDBStreamToLambdaDynamoTable900492E8": Object { - "DeletionPolicy": "Retain", "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": "PAY_PER_REQUEST", - "KeySchema": Array [ + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPool7B7B74A9", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ Object { - "AttributeName": "id", - "KeyType": "HASH", + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", }, ], - "SSESpecification": Object { - "SSEEnabled": true, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Retain", + "Type": "AWS::IAM::Role", }, - "ElasticsearchDomain": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchElasticsearchDomainD539E435": Object { "Metadata": Object { "cfn_nag": Object { "rules_to_suppress": Array [ @@ -292,13 +550,13 @@ Object { "AWS": Array [ Object { "Fn::GetAtt": Array [ - "CognitoAuthorizedRole14E74FE0", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoAuthorizedRole4B91C04E", "Arn", ], }, Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testdynamodbstreamlambdaelasticsearchstackDynamoDBStreamToLambdaLambdaFunctionServiceRoleB674EE63", "Arn", ], }, @@ -327,16 +585,16 @@ Object { "CognitoOptions": Object { "Enabled": true, "IdentityPoolId": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoIdentityPool68C76F43", }, "RoleArn": Object { "Fn::GetAtt": Array [ - "CognitoKibanaConfigureRole62CCE76A", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoKibanaConfigureRoleC8DCD692", "Arn", ], }, "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", }, }, "DomainName": "test-domain", @@ -366,7 +624,7 @@ Object { }, "Type": "AWS::Elasticsearch::Domain", }, - "FreeStorageSpaceTooLowAlarm3410CBE2": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchFreeStorageSpaceTooLowAlarm0DF36C59": Object { "Properties": Object { "AlarmDescription": "A node in your cluster is down to 20 GiB of free storage space.", "ComparisonOperator": "LessThanOrEqualToThreshold", @@ -379,15 +637,15 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "IdentityPoolRoleMapping": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchIdentityPoolRoleMapping31775D80": Object { "Properties": Object { "IdentityPoolId": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoIdentityPool68C76F43", }, "Roles": Object { "authenticated": Object { "Fn::GetAtt": Array [ - "CognitoAuthorizedRole14E74FE0", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoAuthorizedRole4B91C04E", "Arn", ], }, @@ -395,7 +653,7 @@ Object { }, "Type": "AWS::Cognito::IdentityPoolRoleAttachment", }, - "IndexWritesBlockedTooHighAlarm5F7E9A55": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchIndexWritesBlockedTooHighAlarmCD28CBB9": Object { "Properties": Object { "AlarmDescription": "Your cluster is blocking write requests.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -408,7 +666,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "JVMMemoryPressureTooHighAlarm303EEA7C": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchJVMMemoryPressureTooHighAlarmC6CB7B4D": Object { "Properties": Object { "AlarmDescription": "Average JVM memory pressure over last 15 minutes too high. Consider scaling vertically.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -421,198 +679,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "LambdaFunctionBF21E41F": Object { - "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", - ], - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", - }, - ], - }, - }, - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3Bucket87AE2D86", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3VersionKey6EF53907", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters92927de5fcc3aea277bddecb845bee318fb502f7375daedbdafb72c0400bc197S3VersionKey6EF53907", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Environment": Object { - "Variables": Object { - "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", - "DOMAIN_ENDPOINT": Object { - "Fn::GetAtt": Array [ - "ElasticsearchDomain", - "DomainEndpoint", - ], - }, - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", - "Arn", - ], - }, - "Runtime": "nodejs10.x", - }, - "Type": "AWS::Lambda::Function", - }, - "LambdaFunctionDynamoDBEventSourceDynamoDBStreamToLambdaDynamoTableDA56B777DD1406A9": Object { - "Properties": Object { - "BatchSize": 100, - "EventSourceArn": Object { - "Fn::GetAtt": Array [ - "DynamoDBStreamToLambdaDynamoTable900492E8", - "StreamArn", - ], - }, - "FunctionName": Object { - "Ref": "LambdaFunctionBF21E41F", - }, - "StartingPosition": "TRIM_HORIZON", - }, - "Type": "AWS::Lambda::EventSourceMapping", - }, - "LambdaFunctionServiceRole0C4CDE0B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/lambda/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "dynamodb:ListStreams", - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "DynamoDBStreamToLambdaDynamoTable900492E8", - "Arn", - ], - }, - "/stream/*", - ], - ], - }, - }, - Object { - "Action": Array [ - "dynamodb:DescribeStream", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "DynamoDBStreamToLambdaDynamoTable900492E8", - "StreamArn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "Roles": Array [ - Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "MasterCPUUtilizationTooHighAlarm1CE1084B": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchMasterCPUUtilizationTooHighAlarm2BA317F5": Object { "Properties": Object { "AlarmDescription": "Average CPU utilization over last 45 minutes too high. Consider using larger instance types for your dedicated master nodes.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -625,7 +692,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "MasterJVMMemoryPressureTooHighAlarmBB15F770": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchMasterJVMMemoryPressureTooHighAlarmFD25E1C8": Object { "Properties": Object { "AlarmDescription": "Average JVM memory pressure over last 15 minutes too high. Consider scaling vertically.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -638,7 +705,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "StatusRedAlarm4CE918C2": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchStatusRedAlarmDAEB5151": Object { "Properties": Object { "AlarmDescription": "At least one primary shard and its replicas are not allocated to a node. ", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -651,7 +718,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "StatusYellowAlarm2B20F083": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchStatusYellowAlarmB86505F9": Object { "Properties": Object { "AlarmDescription": "At least one replica shard is not allocated to a node.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -664,14 +731,14 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "UserPoolDomain": Object { + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchUserPoolDomain702D3127": Object { "DependsOn": Array [ - "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", ], "Properties": Object { "Domain": "test-domain", "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5", }, }, "Type": "AWS::Cognito::UserPoolDomain", diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts index f5bb58637..62648749a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts @@ -49,7 +49,7 @@ test('check domain names', () => { expect(stack).toHaveResource('AWS::Cognito::UserPoolDomain', { Domain: "test-domain", UserPoolId: { - Ref: "CognitoUserPool53E37E69" + Ref: "testdynamodbstreamlambdaelasticsearchstackLambdaToElasticSearchCognitoUserPoolF99F93E5" } }); diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json index fb78c8e33..92458221c 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json @@ -1,32 +1,6 @@ { "Resources": { - "DynamoDBStreamToLambdaDynamoTable900492E8": { - "Type": "AWS::DynamoDB::Table", - "Properties": { - "KeySchema": [ - { - "AttributeName": "id", - "KeyType": "HASH" - } - ], - "AttributeDefinitions": [ - { - "AttributeName": "id", - "AttributeType": "S" - } - ], - "BillingMode": "PAY_PER_REQUEST", - "SSESpecification": { - "SSEEnabled": true - }, - "StreamSpecification": { - "StreamViewType": "NEW_AND_OLD_IMAGES" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRole7284FB59": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -77,7 +51,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicy9ECA9F26": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -91,7 +65,7 @@ [ { "Fn::GetAtt": [ - "DynamoDBStreamToLambdaDynamoTable900492E8", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaDynamoTable90CA17D8", "Arn" ] }, @@ -109,7 +83,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "DynamoDBStreamToLambdaDynamoTable900492E8", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaDynamoTable90CA17D8", "StreamArn" ] } @@ -117,15 +91,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicy9ECA9F26", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRole7284FB59" } ] } }, - "LambdaFunctionBF21E41F": { + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionE4694B84": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -169,7 +143,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRole7284FB59", "Arn" ] }, @@ -179,7 +153,7 @@ "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", "DOMAIN_ENDPOINT": { "Fn::GetAtt": [ - "ElasticsearchDomain", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchElasticsearchDomainFAB96EC1", "DomainEndpoint" ] } @@ -187,8 +161,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRoleDefaultPolicy9ECA9F26", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRole7284FB59" ], "Metadata": { "cfn_nag": { @@ -201,51 +175,144 @@ } } }, - "LambdaFunctionDynamoDBEventSourcetestdynamodbstreamlambdaelasticsearchkibanastackDynamoDBStreamToLambdaDynamoTableF3692FDE826139F4": { + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionDynamoDBEventSourcetestdynamodbstreamlambdaelasticsearchkibanastacktestdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaDynamoTableEF5268D56B07EBC2": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "EventSourceArn": { "Fn::GetAtt": [ - "DynamoDBStreamToLambdaDynamoTable900492E8", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaDynamoTable90CA17D8", "StreamArn" ] }, "FunctionName": { - "Ref": "LambdaFunctionBF21E41F" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionE4694B84" }, "BatchSize": 100, "StartingPosition": "TRIM_HORIZON" } }, - "CognitoUserPool53E37E69": { + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaDynamoTable90CA17D8": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "SSESpecification": { + "SSEEnabled": true + }, + "StreamSpecification": { + "StreamViewType": "NEW_AND_OLD_IMAGES" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPoolsmsRoleE7EFFA9C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "testdynamodbstreamlambdaelasticsearchkibanastacktestdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool3CD4446B" + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cognito-idp.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "sns-publish" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish" + } + ] + } + } + }, + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72": { "Type": "AWS::Cognito::UserPool", "Properties": { - "LambdaConfig": {}, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": { + "ExternalId": "testdynamodbstreamlambdaelasticsearchkibanastacktestdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool3CD4446B", + "SnsCallerArn": { + "Fn::GetAtt": [ + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPoolsmsRoleE7EFFA9C", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": { "AdvancedSecurityMode": "ENFORCED" + }, + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}" } } }, - "CognitoUserPoolClient5AB59AE4": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPoolClientA7156AE5": { "Type": "AWS::Cognito::UserPoolClient", "Properties": { "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72" } } }, - "CognitoIdentityPool": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoIdentityPool7F08EC45": { "Type": "AWS::Cognito::IdentityPool", "Properties": { "AllowUnauthenticatedIdentities": false, "CognitoIdentityProviders": [ { "ClientId": { - "Ref": "CognitoUserPoolClient5AB59AE4" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPoolClientA7156AE5" }, "ProviderName": { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72", "ProviderName" ] }, @@ -254,19 +321,19 @@ ] } }, - "UserPoolDomain": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchUserPoolDomain0A904A18": { "Type": "AWS::Cognito::UserPoolDomain", "Properties": { "Domain": "myvesperdomain", "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72" } }, "DependsOn": [ - "CognitoUserPool53E37E69" + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72" ] }, - "CognitoAuthorizedRole14E74FE0": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoAuthorizedRole6DD9C03D": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -276,7 +343,7 @@ "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": { - "Ref": "CognitoIdentityPool" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoIdentityPool7F08EC45" } }, "ForAnyValue:StringLike": { @@ -323,23 +390,23 @@ ] } }, - "IdentityPoolRoleMapping": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchIdentityPoolRoleMapping9F79B834": { "Type": "AWS::Cognito::IdentityPoolRoleAttachment", "Properties": { "IdentityPoolId": { - "Ref": "CognitoIdentityPool" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoIdentityPool7F08EC45" }, "Roles": { "authenticated": { "Fn::GetAtt": [ - "CognitoAuthorizedRole14E74FE0", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoAuthorizedRole6DD9C03D", "Arn" ] } } } }, - "CognitoKibanaConfigureRole62CCE76A": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRoleD7825A72": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -356,7 +423,7 @@ } } }, - "CognitoKibanaConfigureRolePolicy76F46A5E": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRolePolicy10C81645": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -380,7 +447,7 @@ "Resource": [ { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72", "Arn" ] }, @@ -398,7 +465,7 @@ }, ":identitypool/", { - "Ref": "CognitoIdentityPool" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoIdentityPool7F08EC45" } ] ] @@ -431,7 +498,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "CognitoKibanaConfigureRole62CCE76A", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRoleD7825A72", "Arn" ] } @@ -439,15 +506,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "CognitoKibanaConfigureRolePolicy76F46A5E", + "PolicyName": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRolePolicy10C81645", "Roles": [ { - "Ref": "CognitoKibanaConfigureRole62CCE76A" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRoleD7825A72" } ] } }, - "ElasticsearchDomain": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchElasticsearchDomainFAB96EC1": { "Type": "AWS::Elasticsearch::Domain", "Properties": { "AccessPolicies": { @@ -459,13 +526,13 @@ "AWS": [ { "Fn::GetAtt": [ - "CognitoAuthorizedRole14E74FE0", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoAuthorizedRole6DD9C03D", "Arn" ] }, { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testdynamodbstreamlambdaelasticsearchkibanaDynamoDBStreamToLambdaLambdaFunctionServiceRole7284FB59", "Arn" ] } @@ -494,16 +561,16 @@ "CognitoOptions": { "Enabled": true, "IdentityPoolId": { - "Ref": "CognitoIdentityPool" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoIdentityPool7F08EC45" }, "RoleArn": { "Fn::GetAtt": [ - "CognitoKibanaConfigureRole62CCE76A", + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoKibanaConfigureRoleD7825A72", "Arn" ] }, "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCognitoUserPool77221A72" } }, "DomainName": "myvesperdomain", @@ -542,7 +609,7 @@ } } }, - "StatusRedAlarm4CE918C2": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchStatusRedAlarmC938FB71": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -555,7 +622,7 @@ "Threshold": 1 } }, - "StatusYellowAlarm2B20F083": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchStatusYellowAlarm71DCDA44": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -568,7 +635,7 @@ "Threshold": 1 } }, - "FreeStorageSpaceTooLowAlarm3410CBE2": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchFreeStorageSpaceTooLowAlarm7AD3AF98": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "LessThanOrEqualToThreshold", @@ -581,7 +648,7 @@ "Threshold": 2000 } }, - "IndexWritesBlockedTooHighAlarm5F7E9A55": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchIndexWritesBlockedTooHighAlarmDEF471CE": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -594,7 +661,7 @@ "Threshold": 1 } }, - "AutomatedSnapshotFailureTooHighAlarmA7918D4F": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchAutomatedSnapshotFailureTooHighAlarmC39154C6": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -607,7 +674,7 @@ "Threshold": 1 } }, - "CPUUtilizationTooHighAlarmA395C469": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchCPUUtilizationTooHighAlarmE30CA506": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -620,7 +687,7 @@ "Threshold": 80 } }, - "JVMMemoryPressureTooHighAlarm303EEA7C": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchJVMMemoryPressureTooHighAlarm569D9580": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -633,7 +700,7 @@ "Threshold": 80 } }, - "MasterCPUUtilizationTooHighAlarm1CE1084B": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchMasterCPUUtilizationTooHighAlarmE5B5DE48": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -646,7 +713,7 @@ "Threshold": 50 } }, - "MasterJVMMemoryPressureTooHighAlarmBB15F770": { + "testdynamodbstreamlambdaelasticsearchkibanaLambdaToElasticSearchMasterJVMMemoryPressureTooHighAlarmE30608AC": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/README.md index 551786f07..d7bf6887a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/README.md @@ -69,8 +69,8 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Retruns an instance of dynamodb.Table created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| +|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Returns an instance of dynamodb.Table created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/lib/index.ts index b5ed15ea8..1d5edf5f8 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/lib/index.ts @@ -72,7 +72,7 @@ export class DynamoDBStreamToLambda extends Construct { constructor(scope: Construct, id: string, props: DynamoDBStreamToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -95,7 +95,7 @@ export class DynamoDBStreamToLambda extends Construct { } /** - * @summary Retruns an instance of dynamodb.Table created by the construct. + * @summary Returns an instance of dynamodb.Table created by the construct. * @returns {dynamodb.Table} Instance of dynamodb.Table created by the construct * @since 0.8.0 * @access public @@ -105,7 +105,7 @@ export class DynamoDBStreamToLambda extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/package.json index 5490e69aa..03b23db00 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-dynamodb-stream-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS DynamoDB Stream to AWS Lambda integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/__snapshots__/dynamodb-stream-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/__snapshots__/dynamodb-stream-lambda.test.js.snap index 5a97cea2a..36c35177d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/__snapshots__/dynamodb-stream-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/__snapshots__/dynamodb-stream-lambda.test.js.snap @@ -17,10 +17,36 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "testlambdadynamodbstackDynamoTable8138E93B": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "AttributeDefinitions": Array [ + Object { + "AttributeName": "id", + "AttributeType": "S", + }, + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": Array [ + Object { + "AttributeName": "id", + "KeyType": "HASH", + }, + ], + "SSESpecification": Object { + "SSEEnabled": true, + }, + "StreamSpecification": Object { + "StreamViewType": "NEW_AND_OLD_IMAGES", + }, + }, + "Type": "AWS::DynamoDB::Table", + "UpdateReplacePolicy": "Retain", + }, + "testlambdadynamodbstackLambdaFunction5DDB3E8D": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", ], "Metadata": Object { "cfn_nag": Object { @@ -79,7 +105,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn", ], }, @@ -87,7 +113,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionDynamoDBEventSourcetestlambdadynamodbstackDynamoTableD6E2BCEF52F21754": Object { + "testlambdadynamodbstackLambdaFunctionDynamoDBEventSourcetestlambdadynamodbstackDynamoTableD6E2BCEF4AB6F3DD": Object { "Properties": Object { "BatchSize": 100, "EventSourceArn": Object { @@ -97,13 +123,13 @@ Object { ], }, "FunctionName": Object { - "Ref": "LambdaFunctionBF21E41F", + "Ref": "testlambdadynamodbstackLambdaFunction5DDB3E8D", }, "StartingPosition": "TRIM_HORIZON", }, "Type": "AWS::Lambda::EventSourceMapping", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -154,7 +180,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -193,41 +219,15 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", }, ], }, "Type": "AWS::IAM::Policy", }, - "testlambdadynamodbstackDynamoTable8138E93B": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": "PAY_PER_REQUEST", - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "SSESpecification": Object { - "SSEEnabled": true, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Retain", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts index d56861454..882057a33 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts @@ -49,7 +49,7 @@ test('check lambda EventSourceMapping', () => { ] }, FunctionName: { - Ref: "LambdaFunctionBF21E41F" + Ref: "testlambdadynamodbstackLambdaFunction5DDB3E8D" }, BatchSize: 100, StartingPosition: "TRIM_HORIZON" @@ -81,7 +81,7 @@ test('check DynamoEventSourceProps override', () => { ] }, FunctionName: { - Ref: "LambdaFunctionBF21E41F" + Ref: "testlambdadynamodbstackLambdaFunction5DDB3E8D" }, BatchSize: 55, StartingPosition: "LATEST" @@ -130,10 +130,10 @@ test('check lambda permission to read dynamodb stream', () => { ], Version: "2012-10-17" }, - PolicyName: "LambdaFunctionServiceRoleDefaultPolicy126C8897", + PolicyName: "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", Roles: [ { - Ref: "LambdaFunctionServiceRole0C4CDE0B" + Ref: "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" } ] }); diff --git a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/integ.no-arguments.expected.json index f8b01d1c1..1bbafbfe3 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-dynamodb-stream-lambda/test/integ.no-arguments.expected.json @@ -1,32 +1,6 @@ { "Resources": { - "testdynamodbstreamlambdaDynamoTable6EB2ED0F": { - "Type": "AWS::DynamoDB::Table", - "Properties": { - "KeySchema": [ - { - "AttributeName": "id", - "KeyType": "HASH" - } - ], - "AttributeDefinitions": [ - { - "AttributeName": "id", - "AttributeType": "S" - } - ], - "BillingMode": "PAY_PER_REQUEST", - "SSESpecification": { - "SSEEnabled": true - }, - "StreamSpecification": { - "StreamViewType": "NEW_AND_OLD_IMAGES" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testdynamodbstreamlambdaLambdaFunctionServiceRole034E525C": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -77,7 +51,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testdynamodbstreamlambdaLambdaFunctionServiceRoleDefaultPolicy90B64ABB": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -117,15 +91,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testdynamodbstreamlambdaLambdaFunctionServiceRoleDefaultPolicy90B64ABB", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testdynamodbstreamlambdaLambdaFunctionServiceRole034E525C" } ] } }, - "LambdaFunctionBF21E41F": { + "testdynamodbstreamlambdaLambdaFunction99034597": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -169,7 +143,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testdynamodbstreamlambdaLambdaFunctionServiceRole034E525C", "Arn" ] }, @@ -181,8 +155,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testdynamodbstreamlambdaLambdaFunctionServiceRoleDefaultPolicy90B64ABB", + "testdynamodbstreamlambdaLambdaFunctionServiceRole034E525C" ], "Metadata": { "cfn_nag": { @@ -195,7 +169,7 @@ } } }, - "LambdaFunctionDynamoDBEventSourcetestdynamodbstreamlambdastacktestdynamodbstreamlambdaDynamoTable99DF98248D8C4DDC": { + "testdynamodbstreamlambdaLambdaFunctionDynamoDBEventSourcetestdynamodbstreamlambdastacktestdynamodbstreamlambdaDynamoTable99DF9824801A5BEE": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "EventSourceArn": { @@ -205,11 +179,37 @@ ] }, "FunctionName": { - "Ref": "LambdaFunctionBF21E41F" + "Ref": "testdynamodbstreamlambdaLambdaFunction99034597" }, "BatchSize": 100, "StartingPosition": "TRIM_HORIZON" } + }, + "testdynamodbstreamlambdaDynamoTable6EB2ED0F": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "SSESpecification": { + "SSEEnabled": true + }, + "StreamSpecification": { + "StreamViewType": "NEW_AND_OLD_IMAGES" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/README.md index bab9cdad3..2d021809e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/README.md @@ -70,8 +70,8 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|eventsRule()|[`events.Rule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.Rule.html)|Retruns an instance of events.Rule created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| +|eventsRule()|[`events.Rule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.Rule.html)|Returns an instance of events.Rule created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/lib/index.ts index 037d09f4e..4aa0fb7e0 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/lib/index.ts @@ -66,7 +66,7 @@ export class EventsRuleToLambda extends Construct { constructor(scope: Construct, id: string, props: EventsRuleToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -91,7 +91,7 @@ export class EventsRuleToLambda extends Construct { } /** - * @summary Retruns an instance of events.Rule created by the construct. + * @summary Returns an instance of events.Rule created by the construct. * @returns {events.Rule} Instance of events.Rule created by the construct * @since 0.8.0 * @access public @@ -101,7 +101,7 @@ export class EventsRuleToLambda extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/package.json index 80bdf4d2c..d554b93c5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-events-rule-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for deploying AWS Events Rule that inveokes AWS Lambda", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-events": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-events": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-events": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-events": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/__snapshots__/events-rule-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/__snapshots__/events-rule-lambda.test.js.snap index b1fe7c586..7a12a5628 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/__snapshots__/events-rule-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/__snapshots__/events-rule-lambda.test.js.snap @@ -17,9 +17,27 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "testeventsrulelambdaEventsRule82B36872": Object { + "Properties": Object { + "ScheduleExpression": "rate(5 minutes)", + "State": "ENABLED", + "Targets": Array [ + Object { + "Arn": Object { + "Fn::GetAtt": Array [ + "testeventsrulelambdaLambdaFunction1A3B9577", + "Arn", + ], + }, + "Id": "Target0", + }, + ], + }, + "Type": "AWS::Events::Rule", + }, + "testeventsrulelambdaLambdaFunction1A3B9577": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405", ], "Metadata": Object { "cfn_nag": Object { @@ -78,7 +96,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405", "Arn", ], }, @@ -86,12 +104,12 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionLambdaInvokePermissionC135C9F1": Object { + "testeventsrulelambdaLambdaFunctionLambdaInvokePermission803B9778": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testeventsrulelambdaLambdaFunction1A3B9577", "Arn", ], }, @@ -105,7 +123,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -156,24 +174,6 @@ Object { }, "Type": "AWS::IAM::Role", }, - "testeventsrulelambdaEventsRule82B36872": Object { - "Properties": Object { - "ScheduleExpression": "rate(5 minutes)", - "State": "ENABLED", - "Targets": Array [ - Object { - "Arn": Object { - "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", - "Arn", - ], - }, - "Id": "Target0", - }, - ], - }, - "Type": "AWS::Events::Rule", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/events-rule-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/events-rule-lambda.test.ts index fcae801a4..ccfc1b548 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/events-rule-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/events-rule-lambda.test.ts @@ -49,7 +49,7 @@ test('check lambda function properties for deploy: true', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405", "Arn" ] }, @@ -71,7 +71,7 @@ test('check lambda function permission for deploy: true', () => { Action: "lambda:InvokeFunction", FunctionName: { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testeventsrulelambdaLambdaFunction1A3B9577", "Arn" ] }, @@ -152,7 +152,7 @@ test('check events rule properties for deploy: true', () => { { Arn: { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testeventsrulelambdaLambdaFunction1A3B9577", "Arn" ] }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/integ.events-rule-no-argument.expected.json b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/integ.events-rule-no-argument.expected.json index f22f4f2ee..c387f37a9 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/integ.events-rule-no-argument.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-events-rule-lambda/test/integ.events-rule-no-argument.expected.json @@ -1,24 +1,6 @@ { "Resources": { - "testeventsrulelambdaEventsRule82B36872": { - "Type": "AWS::Events::Rule", - "Properties": { - "ScheduleExpression": "rate(5 minutes)", - "State": "ENABLED", - "Targets": [ - { - "Arn": { - "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", - "Arn" - ] - }, - "Id": "Target0" - } - ] - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -69,7 +51,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testeventsrulelambdaLambdaFunction1A3B9577": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -113,7 +95,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405", "Arn" ] }, @@ -125,7 +107,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testeventsrulelambdaLambdaFunctionServiceRole61DEA405" ], "Metadata": { "cfn_nag": { @@ -138,13 +120,13 @@ } } }, - "LambdaFunctionLambdaInvokePermissionC135C9F1": { + "testeventsrulelambdaLambdaFunctionLambdaInvokePermission803B9778": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testeventsrulelambdaLambdaFunction1A3B9577", "Arn" ] }, @@ -156,6 +138,24 @@ ] } } + }, + "testeventsrulelambdaEventsRule82B36872": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(5 minutes)", + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::GetAtt": [ + "testeventsrulelambdaLambdaFunction1A3B9577", + "Arn" + ] + }, + "Id": "Target0" + } + ] + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/README.md index 2062dca0e..7721dcd4e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/README.md @@ -71,9 +71,9 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|kinesisFirehose()|[`kinesisfirehose.CfnDeliveryStream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesisfirehose.CfnDeliveryStream.html)|Retruns an instance of kinesisfirehose.CfnDeliveryStream created by the construct| -|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Retruns an instance of s3.Bucket created by the construct| -|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Retruns an instance of iot.CfnTopicRule created by the construct| +|kinesisFirehose()|[`kinesisfirehose.CfnDeliveryStream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesisfirehose.CfnDeliveryStream.html)|Returns an instance of kinesisfirehose.CfnDeliveryStream created by the construct| +|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of s3.Bucket created by the construct| +|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Returns an instance of iot.CfnTopicRule created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/lib/index.ts index 66338a9b4..58ff91db5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/lib/index.ts @@ -115,7 +115,7 @@ export class IotToKinesisFirehoseToS3 extends Construct { } /** - * @summary Retruns an instance of kinesisfirehose.CfnDeliveryStream created by the construct. + * @summary Returns an instance of kinesisfirehose.CfnDeliveryStream created by the construct. * @returns {kinesisfirehose.CfnDeliveryStream} Instance of CfnDeliveryStream created by the construct * @since 0.8.0 * @access public @@ -125,7 +125,7 @@ export class IotToKinesisFirehoseToS3 extends Construct { } /** - * @summary Retruns an instance of s3.Bucket created by the construct. + * @summary Returns an instance of s3.Bucket created by the construct. * @returns {s3.Bucket} Instance of s3.Bucket created by the construct * @since 0.8.0 * @access public @@ -135,7 +135,7 @@ export class IotToKinesisFirehoseToS3 extends Construct { } /** - * @summary Retruns an instance of iot.CfnTopicRule created by the construct. + * @summary Returns an instance of iot.CfnTopicRule created by the construct. * @returns {iot.CfnTopicRule} Instance of CfnTopicRule created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/package.json b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/package.json index 16196415d..37b75e72f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-iot-kinesisfirehose-s3", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS IoT to AWS Kinesis Firehose to AWS S3 integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,16 +52,17 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,12 +72,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/README.md b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/README.md index 57985051b..41357451e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/README.md @@ -77,9 +77,9 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Retruns an instance of iot.CfnTopicRule created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| -|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Retruns an instance of dynamodb.Table created by the construct| +|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Returns an instance of iot.CfnTopicRule created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| +|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Returns an instance of dynamodb.Table created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/lib/index.ts index c83d31540..6bc12e73e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/lib/index.ts @@ -88,7 +88,7 @@ export class IotToLambdaToDynamoDB extends Construct { } /** - * @summary Retruns an instance of iot.CfnTopicRule created by the construct. + * @summary Returns an instance of iot.CfnTopicRule created by the construct. * @returns {iot.CfnTopicRule} Instance of CfnTopicRule created by the construct * @since 0.8.0 * @access public @@ -98,7 +98,7 @@ export class IotToLambdaToDynamoDB extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public @@ -108,7 +108,7 @@ export class IotToLambdaToDynamoDB extends Construct { } /** - * @summary Retruns an instance of dynamodb.Table created by the construct. + * @summary Returns an instance of dynamodb.Table created by the construct. * @returns {dynamodb.Table} Instance of dynamodb.Table created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/package.json b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/package.json index ba1bbc812..53a7e299f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-iot-lambda-dynamodb", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS IoT to AWS Lambda to AWS DyanmoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-iot-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.0" + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-iot-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-iot-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.0" + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-iot-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/__snapshots__/iot-lambda-dynamodb.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/__snapshots__/iot-lambda-dynamodb.test.js.snap index df427159f..da66ff8ed 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/__snapshots__/iot-lambda-dynamodb.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/__snapshots__/iot-lambda-dynamodb.test.js.snap @@ -25,7 +25,7 @@ Object { "Lambda": Object { "FunctionArn": Object { "Fn::GetAtt": Array [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", "Arn", ], }, @@ -39,10 +39,10 @@ Object { }, "Type": "AWS::IoT::TopicRule", }, - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF": Object { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894": Object { "DependsOn": Array [ - "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C", - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", ], "Metadata": Object { "cfn_nag": Object { @@ -104,7 +104,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", "Arn", ], }, @@ -112,12 +112,12 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "testiotlambdadynamodbstackLambdaFunctionLambdaInvokePermissionC33462B4": Object { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionLambdaInvokePermissionBD47A3C8": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", "Arn", ], }, @@ -131,7 +131,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2": Object { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -182,7 +182,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C": Object { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -215,10 +215,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C", + "PolicyName": "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823", "Roles": Array [ Object { - "Ref": "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2", + "Ref": "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", }, ], }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.expected.json b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.expected.json index 96f1fadee..7a5343324 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.expected.json @@ -1,28 +1,6 @@ { "Resources": { - "testiotlambdadynamodbstackIotToLambdaIotTopic74F5E3BB": { - "Type": "AWS::IoT::TopicRule", - "Properties": { - "TopicRulePayload": { - "Actions": [ - { - "Lambda": { - "FunctionArn": { - "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", - "Arn" - ] - } - } - } - ], - "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", - "RuleDisabled": false, - "Sql": "SELECT * FROM 'connectedcar/dtc/#'" - } - } - }, - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2": { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -73,7 +51,7 @@ ] } }, - "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C": { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -107,15 +85,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C", + "PolicyName": "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823", "Roles": [ { - "Ref": "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2" + "Ref": "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA" } ] } }, - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF": { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -159,7 +137,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", "Arn" ] }, @@ -174,8 +152,8 @@ } }, "DependsOn": [ - "testiotlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicyAE674B0C", - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2" + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleDefaultPolicyB43AD823", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA" ], "Metadata": { "cfn_nag": { @@ -188,13 +166,13 @@ } } }, - "testiotlambdadynamodbstackLambdaFunctionLambdaInvokePermissionC33462B4": { + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionLambdaInvokePermissionBD47A3C8": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", "Arn" ] }, @@ -207,6 +185,28 @@ } } }, + "testiotlambdadynamodbstackIotToLambdaIotTopic74F5E3BB": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "Lambda": { + "FunctionArn": { + "Fn::GetAtt": [ + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", + "Arn" + ] + } + } + } + ], + "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", + "RuleDisabled": false, + "Sql": "SELECT * FROM 'connectedcar/dtc/#'" + } + } + }, "testiotlambdadynamodbstackLambdaToDynamoDBDynamoTableE17E5733": { "Type": "AWS::DynamoDB::Table", "Properties": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts index 5cfad31cd..d2b4fe3f5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts @@ -53,7 +53,7 @@ test('check lambda function properties', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionServiceRoleA709DBA2", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", "Arn" ] }, @@ -78,7 +78,7 @@ test('check lambda function permission', () => { Action: "lambda:InvokeFunction", FunctionName: { "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", "Arn" ] }, @@ -159,7 +159,7 @@ test('check iot topic rule properties', () => { Lambda: { FunctionArn: { "Fn::GetAtt": [ - "testiotlambdadynamodbstackLambdaFunctionF1BF28BF", + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", "Arn" ] } diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/README.md index 9bdbbf5b3..01b7b51e4 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/README.md @@ -75,8 +75,8 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Retruns an instance of iot.CfnTopicRule created by the construct| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| +|iotTopicRule()|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Returns an instance of iot.CfnTopicRule created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/lib/index.ts index b9a61de43..3b809426e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/lib/index.ts @@ -66,7 +66,7 @@ export class IotToLambda extends Construct { constructor(scope: Construct, id: string, props: IotToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -89,7 +89,7 @@ export class IotToLambda extends Construct { } /** - * @summary Retruns an instance of iot.CfnTopicRule created by the construct. + * @summary Returns an instance of iot.CfnTopicRule created by the construct. * @returns {iot.CfnTopicRule} Instance of CfnTopicRule created by the construct * @since 0.8.0 * @access public @@ -99,7 +99,7 @@ export class IotToLambda extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/package.json index a34c9bb12..6a96d10ae 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-iot-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS IoT to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-iam": "~1.25.0" + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-iam": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/__snapshots__/iot-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/__snapshots__/iot-lambda.test.js.snap index 88383f6cf..8a87bcf0a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/__snapshots__/iot-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/__snapshots__/iot-lambda.test.js.snap @@ -17,9 +17,31 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "testiotlambdaintegrationIotTopic18B6A735": Object { + "Properties": Object { + "TopicRulePayload": Object { + "Actions": Array [ + Object { + "Lambda": Object { + "FunctionArn": Object { + "Fn::GetAtt": Array [ + "testiotlambdaintegrationLambdaFunctionC5329DBA", + "Arn", + ], + }, + }, + }, + ], + "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", + "RuleDisabled": false, + "Sql": "SELECT * FROM 'connectedcar/dtc/#'", + }, + }, + "Type": "AWS::IoT::TopicRule", + }, + "testiotlambdaintegrationLambdaFunctionC5329DBA": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", ], "Metadata": Object { "cfn_nag": Object { @@ -78,7 +100,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", "Arn", ], }, @@ -86,12 +108,12 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionLambdaInvokePermissionC135C9F1": Object { + "testiotlambdaintegrationLambdaFunctionLambdaInvokePermissionC89CDD23": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testiotlambdaintegrationLambdaFunctionC5329DBA", "Arn", ], }, @@ -105,7 +127,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -156,28 +178,6 @@ Object { }, "Type": "AWS::IAM::Role", }, - "testiotlambdaintegrationIotTopic18B6A735": Object { - "Properties": Object { - "TopicRulePayload": Object { - "Actions": Array [ - Object { - "Lambda": Object { - "FunctionArn": Object { - "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", - "Arn", - ], - }, - }, - }, - ], - "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", - "RuleDisabled": false, - "Sql": "SELECT * FROM 'connectedcar/dtc/#'", - }, - }, - "Type": "AWS::IoT::TopicRule", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/integ.iot-lambda-new-func.expected.json b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/integ.iot-lambda-new-func.expected.json index 046adef40..a5b94e05e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/integ.iot-lambda-new-func.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/integ.iot-lambda-new-func.expected.json @@ -1,28 +1,6 @@ { "Resources": { - "testiotlambdaintegrationIotTopic18B6A735": { - "Type": "AWS::IoT::TopicRule", - "Properties": { - "TopicRulePayload": { - "Actions": [ - { - "Lambda": { - "FunctionArn": { - "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", - "Arn" - ] - } - } - } - ], - "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", - "RuleDisabled": false, - "Sql": "SELECT * FROM 'connectedcar/dtc/#'" - } - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -73,7 +51,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testiotlambdaintegrationLambdaFunctionC5329DBA": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -117,7 +95,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", "Arn" ] }, @@ -129,7 +107,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41" ], "Metadata": { "cfn_nag": { @@ -142,13 +120,13 @@ } } }, - "LambdaFunctionLambdaInvokePermissionC135C9F1": { + "testiotlambdaintegrationLambdaFunctionLambdaInvokePermissionC89CDD23": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testiotlambdaintegrationLambdaFunctionC5329DBA", "Arn" ] }, @@ -160,6 +138,28 @@ ] } } + }, + "testiotlambdaintegrationIotTopic18B6A735": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "Lambda": { + "FunctionArn": { + "Fn::GetAtt": [ + "testiotlambdaintegrationLambdaFunctionC5329DBA", + "Arn" + ] + } + } + } + ], + "Description": "Processing of DTC messages from the AWS Connected Vehicle Solution.", + "RuleDisabled": false, + "Sql": "SELECT * FROM 'connectedcar/dtc/#'" + } + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/iot-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/iot-lambda.test.ts index c975f3658..b133edfae 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/iot-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-iot-lambda/test/iot-lambda.test.ts @@ -78,7 +78,7 @@ test('check lambda function properties for deploy: true', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", "Arn" ] }, @@ -95,7 +95,7 @@ test('check lambda function permission for deploy: true', () => { Action: "lambda:InvokeFunction", FunctionName: { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testiotlambdaintegrationLambdaFunctionC5329DBA", "Arn" ] }, @@ -176,7 +176,7 @@ test('check iot topic rule properties for deploy: true', () => { Lambda: { FunctionArn: { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testiotlambdaintegrationLambdaFunctionC5329DBA", "Arn" ] } diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json index 74fcbbb6d..c5db98572 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-kinesisfirehose-s3-and-kinesisanalytics", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Firehose delivery stream and (1) an Amazon S3 bucket, and (2) an Amazon Kinesis Data Analytics application.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,17 +52,18 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kinesisanalytics": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kinesisanalytics": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,13 +73,14 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kinesisanalytics": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kinesisanalytics": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-solutions-konstruk/aws-kinesisfirehose-s3": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/README.md index 4c2f0aeb7..13a8c88aa 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/README.md @@ -59,8 +59,8 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|kinesisFirehose()|[`kinesisfirehose.CfnDeliveryStream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesisfirehose.CfnDeliveryStream.html)|Retruns an instance of kinesisfirehose.CfnDeliveryStream created by the construct| -|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Retruns an instance of s3.Bucket created by the construct| +|kinesisFirehose()|[`kinesisfirehose.CfnDeliveryStream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesisfirehose.CfnDeliveryStream.html)|Returns an instance of kinesisfirehose.CfnDeliveryStream created by the construct| +|bucket()|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of s3.Bucket created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/lib/index.ts index dd4988189..c32d3af0e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/lib/index.ts @@ -132,14 +132,14 @@ export class KinesisFirehoseToS3 extends Construct { } /** - * Retruns an instance of kinesisfirehose.CfnDeliveryStream created by the construct + * Returns an instance of kinesisfirehose.CfnDeliveryStream created by the construct */ public kinesisFirehose(): kinesisfirehose.CfnDeliveryStream { return this.firehose; } /** - * Retruns an instance of s3.Bucket created by the construct + * Returns an instance of s3.Bucket created by the construct */ public bucket(): s3.Bucket { return this.s3Bucket; diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/package.json b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/package.json index 6379af08b..0b3b0f1e4 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisfirehose-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-kinesisfirehose-s3", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Firehose delivery stream and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,15 +52,16 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,11 +71,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/lib/index.ts index 544a81b5f..199803c54 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/lib/index.ts @@ -86,27 +86,27 @@ export class KinesisStreamsToLambda extends Construct { super(scope, id); // Setup the encryption key - this.encryptionKey = defaults.buildEncryptionKey(scope, { + this.encryptionKey = defaults.buildEncryptionKey(this, { encryptionKeyProps: props.encryptionKeyProps }); // Setup the Kinesis Stream - this.kinesisStream = defaults.buildKinesisStream(scope, { + this.kinesisStream = defaults.buildKinesisStream(this, { encryptionKey: this.encryptionKey, kinesisStreamProps: props.kinesisStreamProps }); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps }); // Add the Lambda event source mapping - const eventSourceProps = overrideProps(defaults.DefaultKinesisEventSourceProps, props.eventSourceProps); - eventSourceProps.eventSourceArn = this.kinesisStream.streamArn; - eventSourceProps.functionName = this.fn.functionName; + const eventSourceProps = (props.eventSourceProps) ? + overrideProps(defaults.DefaultKinesisEventSourceProps(this.kinesisStream.streamArn), props.eventSourceProps) : + defaults.DefaultKinesisEventSourceProps(this.kinesisStream.streamArn); this.fn.addEventSourceMapping('LambdaKinesisEventSourceMapping', eventSourceProps); // Add permissions for the Lambda function to access Kinesis diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/package.json index 6e65b26bb..3fea2344a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-kinesisstreams-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Stream and an AWS Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,16 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/__snapshots__/test.kinesisstreams-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/__snapshots__/test.kinesisstreams-lambda.test.js.snap index 7fdd4bd79..300bbac1a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/__snapshots__/test.kinesisstreams-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/__snapshots__/test.kinesisstreams-lambda.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Pattern deployment 1`] = ` +exports[`Pattern minimal deployment 1`] = ` Object { "Parameters": Object { "AssetParametersdfe828a7d00b0da7a6e92dc1decf39ec907e4edc6006faea8631d4dabd7f4fcdArtifactHashEA3A5944": Object { @@ -17,7 +17,7 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { + "testkinesisstreamslambdaEncryptionKey6CFF01F7": Object { "DeletionPolicy": "Retain", "Properties": Object { "EnableKeyRotation": true, @@ -68,7 +68,7 @@ Object { "Principal": Object { "AWS": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F", "Arn", ], }, @@ -82,7 +82,7 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "KinesisStream46752A3E": Object { + "testkinesisstreamslambdaKinesisStream76FFCAB1": Object { "Properties": Object { "RetentionPeriodHours": 24, "ShardCount": 1, @@ -90,7 +90,7 @@ Object { "EncryptionType": "KMS", "KeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testkinesisstreamslambdaEncryptionKey6CFF01F7", "Arn", ], }, @@ -98,10 +98,10 @@ Object { }, "Type": "AWS::Kinesis::Stream", }, - "LambdaFunctionBF21E41F": Object { + "testkinesisstreamslambdaLambdaFunction02E4DD2D": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "testkinesisstreamslambdaLambdaFunctionServiceRoleDefaultPolicyE2BE8F65", + "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F", ], "Metadata": Object { "cfn_nag": Object { @@ -160,7 +160,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F", "Arn", ], }, @@ -168,23 +168,66 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionLambdaKinesisEventSourceMappingE4E81D45": Object { + "testkinesisstreamslambdaLambdaFunctionLambdaKinesisEventSourceMapping06EA601A": Object { "Properties": Object { - "BatchSize": 1, "EventSourceArn": Object { "Fn::GetAtt": Array [ - "KinesisStream46752A3E", + "testkinesisstreamslambdaKinesisStream76FFCAB1", "Arn", ], }, "FunctionName": Object { - "Ref": "LambdaFunctionBF21E41F", + "Ref": "testkinesisstreamslambdaLambdaFunction02E4DD2D", }, - "StartingPosition": "TRIM_HORIZON", }, "Type": "AWS::Lambda::EventSourceMapping", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testkinesisstreamslambdaLambdaFunctionPolicyF7EF016E": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W12", + "reason": "The kinesis:ListStreams action requires a wildcard resource.", + }, + ], + }, + }, + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "kinesis:GetRecords", + "kinesis:GetShardIterator", + "kinesis:DescribeStream", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "testkinesisstreamslambdaKinesisStream76FFCAB1", + "Arn", + ], + }, + }, + Object { + "Action": "kinesis:ListStreams", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "testkinesisstreamslambdaLambdaFunctionPolicyF7EF016E", + "Roles": Array [ + Object { + "Ref": "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -235,20 +278,22 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "testkinesisstreamslambdaLambdaFunctionServiceRoleDefaultPolicyE2BE8F65": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ Object { "Action": Array [ - "kinesis:DescribeStream", + "kinesis:DescribeStreamSummary", "kinesis:GetRecords", "kinesis:GetShardIterator", + "kinesis:ListShards", + "kinesis:SubscribeToShard", ], "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "KinesisStream46752A3E", + "testkinesisstreamslambdaKinesisStream76FFCAB1", "Arn", ], }, @@ -258,7 +303,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testkinesisstreamslambdaEncryptionKey6CFF01F7", "Arn", ], }, @@ -266,55 +311,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "Roles": Array [ - Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "testkinesisstreamslambdaLambdaFunctionPolicyF7EF016E": Object { - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W12", - "reason": "The kinesis:ListStreams action requires a wildcard resource.", - }, - ], - }, - }, - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "kinesis:DescribeStream", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "KinesisStream46752A3E", - "Arn", - ], - }, - }, - Object { - "Action": "kinesis:ListStreams", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "testkinesisstreamslambdaLambdaFunctionPolicyF7EF016E", + "PolicyName": "testkinesisstreamslambdaLambdaFunctionServiceRoleDefaultPolicyE2BE8F65", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "testkinesisstreamslambdaLambdaFunctionServiceRoleD083672F", }, ], }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/integ.deployFunction.expected.json index f0cce5a64..74499c45d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/integ.deployFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/integ.deployFunction.expected.json @@ -1,52 +1,7 @@ { "Description": "Integration Test for aws-kinesisstreams-lambda", "Resources": { - "testkslambdaLambdaFunctionPolicyDC40446F": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "kinesis:DescribeStream" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "KinesisStream46752A3E", - "Arn" - ] - } - }, - { - "Action": "kinesis:ListStreams", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "testkslambdaLambdaFunctionPolicyDC40446F", - "Roles": [ - { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" - } - ] - }, - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W12", - "reason": "The kinesis:ListStreams action requires a wildcard resource." - } - ] - } - } - }, - "EncryptionKey1B843E66": { + "testkslambdaEncryptionKey4161DDEB": { "Type": "AWS::KMS::Key", "Properties": { "KeyPolicy": { @@ -96,7 +51,7 @@ "Principal": { "AWS": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testkslambdaLambdaFunctionServiceRole329F6464", "Arn" ] } @@ -111,7 +66,7 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "KinesisStream46752A3E": { + "testkslambdaKinesisStreamE607D575": { "Type": "AWS::Kinesis::Stream", "Properties": { "ShardCount": 1, @@ -120,14 +75,14 @@ "EncryptionType": "KMS", "KeyId": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testkslambdaEncryptionKey4161DDEB", "Arn" ] } } } }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testkslambdaLambdaFunctionServiceRole329F6464": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -178,21 +133,23 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testkslambdaLambdaFunctionServiceRoleDefaultPolicy06A105D0": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { "Statement": [ { "Action": [ - "kinesis:DescribeStream", + "kinesis:DescribeStreamSummary", "kinesis:GetRecords", - "kinesis:GetShardIterator" + "kinesis:GetShardIterator", + "kinesis:ListShards", + "kinesis:SubscribeToShard" ], "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "KinesisStream46752A3E", + "testkslambdaKinesisStreamE607D575", "Arn" ] } @@ -202,7 +159,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testkslambdaEncryptionKey4161DDEB", "Arn" ] } @@ -210,15 +167,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testkslambdaLambdaFunctionServiceRoleDefaultPolicy06A105D0", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testkslambdaLambdaFunctionServiceRole329F6464" } ] } }, - "LambdaFunctionBF21E41F": { + "testkslambdaLambdaFunction995A7276": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -262,7 +219,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testkslambdaLambdaFunctionServiceRole329F6464", "Arn" ] }, @@ -274,8 +231,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testkslambdaLambdaFunctionServiceRoleDefaultPolicy06A105D0", + "testkslambdaLambdaFunctionServiceRole329F6464" ], "Metadata": { "cfn_nag": { @@ -288,21 +245,66 @@ } } }, - "LambdaFunctionLambdaKinesisEventSourceMappingE4E81D45": { + "testkslambdaLambdaFunctionLambdaKinesisEventSourceMapping70D66039": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "EventSourceArn": { "Fn::GetAtt": [ - "KinesisStream46752A3E", + "testkslambdaKinesisStreamE607D575", "Arn" ] }, "FunctionName": { - "Ref": "LambdaFunctionBF21E41F" + "Ref": "testkslambdaLambdaFunction995A7276" }, "BatchSize": 1, "StartingPosition": "TRIM_HORIZON" } + }, + "testkslambdaLambdaFunctionPolicyDC40446F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:GetRecords", + "kinesis:GetShardIterator", + "kinesis:DescribeStream" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testkslambdaKinesisStreamE607D575", + "Arn" + ] + } + }, + { + "Action": "kinesis:ListStreams", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testkslambdaLambdaFunctionPolicyDC40446F", + "Roles": [ + { + "Ref": "testkslambdaLambdaFunctionServiceRole329F6464" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "The kinesis:ListStreams action requires a wildcard resource." + } + ] + } + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts index 851b35768..3496a455a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts @@ -20,23 +20,17 @@ import * as lambda from '@aws-cdk/aws-lambda'; import '@aws-cdk/assert/jest'; // -------------------------------------------------------------- -// Pattern deployment +// Pattern minimal deployment // -------------------------------------------------------------- -test('Pattern deployment', () => { +test('Pattern minimal deployment', () => { // Initial setup const stack = new Stack(); const props: KinesisStreamsToLambdaProps = { - encryptionKeyProps: {}, - kinesisStreamProps: {}, deployLambda: true, lambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, handler: 'index.handler', code: lambda.Code.asset(`${__dirname}/lambda`) - }, - eventSourceProps: { - startingPosition: StartingPosition.TRIM_HORIZON, - batchSize: 1 } }; new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/README.md b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/README.md index 58e0f28df..94c615d1c 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/README.md @@ -68,8 +68,8 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| -|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Retruns an instance of dynamodb.Table created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| +|dynamoTable()|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Returns an instance of dynamodb.Table created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/lib/index.ts index 8832735ec..9d822f260 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/lib/index.ts @@ -65,7 +65,7 @@ export class LambdaToDynamoDB extends Construct { constructor(scope: Construct, id: string, props: LambdaToDynamoDBProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -82,10 +82,23 @@ export class LambdaToDynamoDB extends Construct { this.fn.addEnvironment('DDB_TABLE_NAME', this.table.tableName); this.table.grantReadWriteData(this.fn.grantPrincipal); + + // Conditional metadata for cfn_nag + if (props.dynamoTableProps?.billingMode === dynamodb.BillingMode.PROVISIONED) { + const cfnTable: dynamodb.CfnTable = this.table.node.findChild('Resource') as dynamodb.CfnTable; + cfnTable.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W73', + reason: `PROVISIONED billing mode is a default and is not explicitly applied as a setting.` + }] + } + }; + } } /** - * @summary Retruns an instance of dynamodb.Table created by the construct. + * @summary Returns an instance of dynamodb.Table created by the construct. * @returns {dynamodb.Table} Instance of dynamodb.Table created by the construct * @since 0.8.0 * @access public @@ -95,7 +108,7 @@ export class LambdaToDynamoDB extends Construct { } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of lambda.Function created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/package.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/package.json index cb43a8a40..004f9a249 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-lambda-dynamodb", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Lambda to AWS DynamoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,13 +53,14 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -69,9 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/__snapshots__/lambda-dynamodb.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/__snapshots__/lambda-dynamodb.test.js.snap index 5c8fbe976..2205ba976 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/__snapshots__/lambda-dynamodb.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/__snapshots__/lambda-dynamodb.test.js.snap @@ -17,10 +17,33 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "testlambdadynamodbstackDynamoTable8138E93B": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "AttributeDefinitions": Array [ + Object { + "AttributeName": "id", + "AttributeType": "S", + }, + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": Array [ + Object { + "AttributeName": "id", + "KeyType": "HASH", + }, + ], + "SSESpecification": Object { + "SSEEnabled": true, + }, + }, + "Type": "AWS::DynamoDB::Table", + "UpdateReplacePolicy": "Retain", + }, + "testlambdadynamodbstackLambdaFunction5DDB3E8D": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", ], "Metadata": Object { "cfn_nag": Object { @@ -82,7 +105,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn", ], }, @@ -90,7 +113,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -141,7 +164,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -174,38 +197,15 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", }, ], }, "Type": "AWS::IAM::Policy", }, - "testlambdadynamodbstackDynamoTable8138E93B": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": "PAY_PER_REQUEST", - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "SSESpecification": Object { - "SSEEnabled": true, - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Retain", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.add-secondary-index.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.add-secondary-index.expected.json index 7f5c82981..3b1d096b4 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.add-secondary-index.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.add-secondary-index.expected.json @@ -1,47 +1,6 @@ { "Resources": { - "testlambdadynamodbstackDynamoTable8138E93B": { - "Type": "AWS::DynamoDB::Table", - "Properties": { - "KeySchema": [ - { - "AttributeName": "id", - "KeyType": "HASH" - } - ], - "AttributeDefinitions": [ - { - "AttributeName": "id", - "AttributeType": "S" - }, - { - "AttributeName": "id2", - "AttributeType": "S" - } - ], - "BillingMode": "PAY_PER_REQUEST", - "GlobalSecondaryIndexes": [ - { - "IndexName": "test_id2", - "KeySchema": [ - { - "AttributeName": "id2", - "KeyType": "HASH" - } - ], - "Projection": { - "ProjectionType": "ALL" - } - } - ], - "SSESpecification": { - "SSEEnabled": true - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -92,7 +51,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -137,15 +96,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" } ] } }, - "LambdaFunctionBF21E41F": { + "testlambdadynamodbstackLambdaFunction5DDB3E8D": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -189,7 +148,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn" ] }, @@ -204,8 +163,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" ], "Metadata": { "cfn_nag": { @@ -217,6 +176,47 @@ ] } } + }, + "testlambdadynamodbstackDynamoTable8138E93B": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + }, + { + "AttributeName": "id2", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "GlobalSecondaryIndexes": [ + { + "IndexName": "test_id2", + "KeySchema": [ + { + "AttributeName": "id2", + "KeyType": "HASH" + } + ], + "Projection": { + "ProjectionType": "ALL" + } + } + ], + "SSESpecification": { + "SSEEnabled": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.no-arguments.expected.json index a95e1b63f..1435c7cf6 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.no-arguments.expected.json @@ -1,29 +1,6 @@ { "Resources": { - "testlambdadynamodbstackDynamoTable8138E93B": { - "Type": "AWS::DynamoDB::Table", - "Properties": { - "KeySchema": [ - { - "AttributeName": "id", - "KeyType": "HASH" - } - ], - "AttributeDefinitions": [ - { - "AttributeName": "id", - "AttributeType": "S" - } - ], - "BillingMode": "PAY_PER_REQUEST", - "SSESpecification": { - "SSEEnabled": true - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -74,7 +51,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -108,15 +85,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" } ] } }, - "LambdaFunctionBF21E41F": { + "testlambdadynamodbstackLambdaFunction5DDB3E8D": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -160,7 +137,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn" ] }, @@ -175,8 +152,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" ], "Metadata": { "cfn_nag": { @@ -188,6 +165,29 @@ ] } } + }, + "testlambdadynamodbstackDynamoTable8138E93B": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST", + "SSESpecification": { + "SSEEnabled": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.set-billing-mode.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.set-billing-mode.expected.json index 587990468..ac826c223 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.set-billing-mode.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/integ.set-billing-mode.expected.json @@ -24,9 +24,19 @@ } }, "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W73", + "reason": "PROVISIONED billing mode is a default and is not explicitly applied as a setting." + } + ] + } + } }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -77,7 +87,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -111,15 +121,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" } ] } }, - "LambdaFunctionBF21E41F": { + "testlambdadynamodbstackLambdaFunction5DDB3E8D": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -163,7 +173,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn" ] }, @@ -178,8 +188,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdadynamodbstackLambdaFunctionServiceRoleDefaultPolicy547FB7F4", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1" ], "Metadata": { "cfn_nag": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts index 8952d2223..0fb55c051 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts @@ -70,7 +70,7 @@ test('check lambda function properties for deploy: true', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdadynamodbstackLambdaFunctionServiceRole758347A1", "Arn" ] }, @@ -290,7 +290,7 @@ test('check deploy = true and no prop', () => { Handler: "index.handler", Role: { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testiotlambdastackLambdaFunctionServiceRoleF72A85A9", "Arn" ] }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/README.md b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/README.md index 5ebec61d8..5ec92d388 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/README.md @@ -70,12 +70,12 @@ _Parameters_ | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Retruns an instance of lambda.Function created by the construct| -|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Retruns an instance of cognito.UserPool created by the construct| -|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Retruns an instance of cognito.UserPoolClient created by the construct| -|identityPool()|[`cognito.CfnIdentityPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.CfnIdentityPool.html)|Retruns an instance of cognito.CfnIdentityPool created by the construct| -|elasticsearchDomain()|[`elasticsearch.CfnDomain`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticsearch.CfnDomain.html)|Retruns an instance of elasticsearch.CfnDomain created by the construct| -|cloudwatchAlarms()|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Retruns a list of cloudwatch.Alarm created by the construct| +|lambdaFunction()|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct| +|userPool()|[`cognito.UserPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPool.html)|Returns an instance of cognito.UserPool created by the construct| +|userPoolClient()|[`cognito.UserPoolClient`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.UserPoolClient.html)|Returns an instance of cognito.UserPoolClient created by the construct| +|identityPool()|[`cognito.CfnIdentityPool`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cognito.CfnIdentityPool.html)|Returns an instance of cognito.CfnIdentityPool created by the construct| +|elasticsearchDomain()|[`elasticsearch.CfnDomain`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticsearch.CfnDomain.html)|Returns an instance of elasticsearch.CfnDomain created by the construct| +|cloudwatchAlarms()|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of cloudwatch.Alarm created by the construct| ## Architecture ![Architecture Diagram](architecture.png) diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/lib/index.ts index 7fe41e234..17ba52ae8 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/lib/index.ts @@ -77,7 +77,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { constructor(scope: Construct, id: string, props: LambdaToElasticSearchAndKibanaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -86,17 +86,17 @@ export class LambdaToElasticSearchAndKibana extends Construct { // Find the lambda service Role ARN const lambdaFunctionRoleARN = this.fn.role?.roleArn; - this.userpool = defaults.buildUserPool(scope); - this.userpoolclient = defaults.buildUserPoolClient(scope, this.userpool); - this.identitypool = defaults.buildIdentityPool(scope, this.userpool, this.userpoolclient); + this.userpool = defaults.buildUserPool(this); + this.userpoolclient = defaults.buildUserPoolClient(this, this.userpool); + this.identitypool = defaults.buildIdentityPool(this, this.userpool, this.userpoolclient); - const cognitoAuthorizedRole: Role = defaults.setupCognitoForElasticSearch(scope, props.domainName, { + const cognitoAuthorizedRole: Role = defaults.setupCognitoForElasticSearch(this, props.domainName, { userpool: this.userpool, identitypool: this.identitypool, userpoolclient: this.userpoolclient }); - this.elasticsearch = defaults.buildElasticSearch(scope, props.domainName, { + this.elasticsearch = defaults.buildElasticSearch(this, props.domainName, { userpool: this.userpool, identitypool: this.identitypool, cognitoAuthorizedRoleARN: cognitoAuthorizedRole.roleArn, @@ -106,11 +106,11 @@ export class LambdaToElasticSearchAndKibana extends Construct { this.fn.addEnvironment('DOMAIN_ENDPOINT', this.elasticsearch.attrDomainEndpoint); // Deploy best practices CW Alarms for ES - this.cwAlarms = defaults.buildElasticSearchCWAlarms(scope); + this.cwAlarms = defaults.buildElasticSearchCWAlarms(this); } /** - * @summary Retruns an instance of lambda.Function created by the construct. + * @summary Returns an instance of lambda.Function created by the construct. * @returns {lambda.Function} Instance of Function created by the construct * @since 0.8.0 * @access public @@ -120,7 +120,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.UserPool created by the construct. + * @summary Returns an instance of cognito.UserPool created by the construct. * @returns {cognito.UserPool} Instance of UserPool created by the construct * @since 0.8.0 * @access public @@ -130,7 +130,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.UserPoolClient created by the construct. + * @summary Returns an instance of cognito.UserPoolClient created by the construct. * @returns {cognito.UserPoolClient} Instance of UserPoolClient created by the construct * @since 0.8.0 * @access public @@ -140,7 +140,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of cognito.CfnIdentityPool created by the construct. + * @summary Returns an instance of cognito.CfnIdentityPool created by the construct. * @returns {cognito.CfnIdentityPool} Instance of CfnIdentityPool created by the construct * @since 0.8.0 * @access public @@ -150,7 +150,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns an instance of elasticsearch.CfnDomain created by the construct. + * @summary Returns an instance of elasticsearch.CfnDomain created by the construct. * @returns {elasticsearch.CfnDomain} Instance of CfnDomain created by the construct * @since 0.8.0 * @access public @@ -160,7 +160,7 @@ export class LambdaToElasticSearchAndKibana extends Construct { } /** - * @summary Retruns a list of cloudwatch.Alarm created by the construct. + * @summary Returns a list of cloudwatch.Alarm created by the construct. * @returns {cloudwatch.Alarm[]} List of cloudwatch.Alarm created by the construct * @since 0.8.0 * @access public diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/package.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/package.json index 3ac3db569..30f802b3a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS Lambda to AWS Elasticsearch with Kibana integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/__snapshots__/lambda-elasticsearch-kibana.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/__snapshots__/lambda-elasticsearch-kibana.test.js.snap index 9380edc79..bd735cd80 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/__snapshots__/lambda-elasticsearch-kibana.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/__snapshots__/lambda-elasticsearch-kibana.test.js.snap @@ -17,7 +17,7 @@ Object { }, }, "Resources": Object { - "AutomatedSnapshotFailureTooHighAlarmA7918D4F": Object { + "testlambdaelasticsearchstackAutomatedSnapshotFailureTooHighAlarmE1525DBA": Object { "Properties": Object { "AlarmDescription": "An automated snapshot failed. This failure is often the result of a red cluster health status.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -30,7 +30,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "CPUUtilizationTooHighAlarmA395C469": Object { + "testlambdaelasticsearchstackCPUUtilizationTooHighAlarm25C597E5": Object { "Properties": Object { "AlarmDescription": "100% CPU utilization is not uncommon, but sustained high usage is problematic. Consider using larger instance types or adding instances.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -43,7 +43,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "CognitoAuthorizedRole14E74FE0": Object { + "testlambdaelasticsearchstackCognitoAuthorizedRole48A260E1": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -55,7 +55,7 @@ Object { }, "StringEquals": Object { "cognito-identity.amazonaws.com:aud": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testlambdaelasticsearchstackCognitoIdentityPool7A260383", }, }, }, @@ -100,17 +100,17 @@ Object { }, "Type": "AWS::IAM::Role", }, - "CognitoIdentityPool": Object { + "testlambdaelasticsearchstackCognitoIdentityPool7A260383": Object { "Properties": Object { "AllowUnauthenticatedIdentities": false, "CognitoIdentityProviders": Array [ Object { "ClientId": Object { - "Ref": "CognitoUserPoolClient5AB59AE4", + "Ref": "testlambdaelasticsearchstackCognitoUserPoolClient6610371B", }, "ProviderName": Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "testlambdaelasticsearchstackCognitoUserPool05D1387E", "ProviderName", ], }, @@ -120,7 +120,7 @@ Object { }, "Type": "AWS::Cognito::IdentityPool", }, - "CognitoKibanaConfigureRole62CCE76A": Object { + "testlambdaelasticsearchstackCognitoKibanaConfigureRole72380E63": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -137,7 +137,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "CognitoKibanaConfigureRolePolicy76F46A5E": Object { + "testlambdaelasticsearchstackCognitoKibanaConfigureRolePolicyE3A46E8D": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -160,7 +160,7 @@ Object { "Resource": Array [ Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "testlambdaelasticsearchstackCognitoUserPool05D1387E", "Arn", ], }, @@ -178,7 +178,7 @@ Object { }, ":identitypool/", Object { - "Ref": "CognitoIdentityPool", + "Ref": "testlambdaelasticsearchstackCognitoIdentityPool7A260383", }, ], ], @@ -211,7 +211,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "CognitoKibanaConfigureRole62CCE76A", + "testlambdaelasticsearchstackCognitoKibanaConfigureRole72380E63", "Arn", ], }, @@ -219,33 +219,100 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "CognitoKibanaConfigureRolePolicy76F46A5E", + "PolicyName": "testlambdaelasticsearchstackCognitoKibanaConfigureRolePolicyE3A46E8D", "Roles": Array [ Object { - "Ref": "CognitoKibanaConfigureRole62CCE76A", + "Ref": "testlambdaelasticsearchstackCognitoKibanaConfigureRole72380E63", }, ], }, "Type": "AWS::IAM::Policy", }, - "CognitoUserPool53E37E69": Object { + "testlambdaelasticsearchstackCognitoUserPool05D1387E": Object { "Properties": Object { - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "testlambdaelasticsearchstackCognitoUserPoolE85DABFF", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "testlambdaelasticsearchstackCognitoUserPoolsmsRoleDEC8C9B4", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, - "CognitoUserPoolClient5AB59AE4": Object { + "testlambdaelasticsearchstackCognitoUserPoolClient6610371B": Object { "Properties": Object { "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "testlambdaelasticsearchstackCognitoUserPool05D1387E", }, }, "Type": "AWS::Cognito::UserPoolClient", }, - "ElasticsearchDomain": Object { + "testlambdaelasticsearchstackCognitoUserPoolsmsRoleDEC8C9B4": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], + }, + }, + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "testlambdaelasticsearchstackCognitoUserPoolE85DABFF", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testlambdaelasticsearchstackElasticsearchDomain2DE7011B": Object { "Metadata": Object { "cfn_nag": Object { "rules_to_suppress": Array [ @@ -266,13 +333,13 @@ Object { "AWS": Array [ Object { "Fn::GetAtt": Array [ - "CognitoAuthorizedRole14E74FE0", + "testlambdaelasticsearchstackCognitoAuthorizedRole48A260E1", "Arn", ], }, Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdaelasticsearchstackLambdaFunctionServiceRoleEB1E3355", "Arn", ], }, @@ -301,16 +368,16 @@ Object { "CognitoOptions": Object { "Enabled": true, "IdentityPoolId": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testlambdaelasticsearchstackCognitoIdentityPool7A260383", }, "RoleArn": Object { "Fn::GetAtt": Array [ - "CognitoKibanaConfigureRole62CCE76A", + "testlambdaelasticsearchstackCognitoKibanaConfigureRole72380E63", "Arn", ], }, "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "testlambdaelasticsearchstackCognitoUserPool05D1387E", }, }, "DomainName": "test-domain", @@ -340,7 +407,7 @@ Object { }, "Type": "AWS::Elasticsearch::Domain", }, - "FreeStorageSpaceTooLowAlarm3410CBE2": Object { + "testlambdaelasticsearchstackFreeStorageSpaceTooLowAlarmB0688A0C": Object { "Properties": Object { "AlarmDescription": "A node in your cluster is down to 20 GiB of free storage space.", "ComparisonOperator": "LessThanOrEqualToThreshold", @@ -353,15 +420,15 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "IdentityPoolRoleMapping": Object { + "testlambdaelasticsearchstackIdentityPoolRoleMapping1553C88A": Object { "Properties": Object { "IdentityPoolId": Object { - "Ref": "CognitoIdentityPool", + "Ref": "testlambdaelasticsearchstackCognitoIdentityPool7A260383", }, "Roles": Object { "authenticated": Object { "Fn::GetAtt": Array [ - "CognitoAuthorizedRole14E74FE0", + "testlambdaelasticsearchstackCognitoAuthorizedRole48A260E1", "Arn", ], }, @@ -369,7 +436,7 @@ Object { }, "Type": "AWS::Cognito::IdentityPoolRoleAttachment", }, - "IndexWritesBlockedTooHighAlarm5F7E9A55": Object { + "testlambdaelasticsearchstackIndexWritesBlockedTooHighAlarm204AB403": Object { "Properties": Object { "AlarmDescription": "Your cluster is blocking write requests.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -382,7 +449,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "JVMMemoryPressureTooHighAlarm303EEA7C": Object { + "testlambdaelasticsearchstackJVMMemoryPressureTooHighAlarmFB8617D3": Object { "Properties": Object { "AlarmDescription": "Average JVM memory pressure over last 15 minutes too high. Consider scaling vertically.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -395,9 +462,9 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "LambdaFunctionBF21E41F": Object { + "testlambdaelasticsearchstackLambdaFunction5CA5683F": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdaelasticsearchstackLambdaFunctionServiceRoleEB1E3355", ], "Metadata": Object { "cfn_nag": Object { @@ -453,7 +520,7 @@ Object { "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", "DOMAIN_ENDPOINT": Object { "Fn::GetAtt": Array [ - "ElasticsearchDomain", + "testlambdaelasticsearchstackElasticsearchDomain2DE7011B", "DomainEndpoint", ], }, @@ -462,7 +529,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdaelasticsearchstackLambdaFunctionServiceRoleEB1E3355", "Arn", ], }, @@ -470,7 +537,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testlambdaelasticsearchstackLambdaFunctionServiceRoleEB1E3355": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -521,7 +588,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "MasterCPUUtilizationTooHighAlarm1CE1084B": Object { + "testlambdaelasticsearchstackMasterCPUUtilizationTooHighAlarm9F5EF826": Object { "Properties": Object { "AlarmDescription": "Average CPU utilization over last 45 minutes too high. Consider using larger instance types for your dedicated master nodes.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -534,7 +601,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "MasterJVMMemoryPressureTooHighAlarmBB15F770": Object { + "testlambdaelasticsearchstackMasterJVMMemoryPressureTooHighAlarmECFF41A2": Object { "Properties": Object { "AlarmDescription": "Average JVM memory pressure over last 15 minutes too high. Consider scaling vertically.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -547,7 +614,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "StatusRedAlarm4CE918C2": Object { + "testlambdaelasticsearchstackStatusRedAlarmD3149716": Object { "Properties": Object { "AlarmDescription": "At least one primary shard and its replicas are not allocated to a node. ", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -560,7 +627,7 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "StatusYellowAlarm2B20F083": Object { + "testlambdaelasticsearchstackStatusYellowAlarm75AD016C": Object { "Properties": Object { "AlarmDescription": "At least one replica shard is not allocated to a node.", "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -573,14 +640,14 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, - "UserPoolDomain": Object { + "testlambdaelasticsearchstackUserPoolDomainD67735BF": Object { "DependsOn": Array [ - "CognitoUserPool53E37E69", + "testlambdaelasticsearchstackCognitoUserPool05D1387E", ], "Properties": Object { "Domain": "test-domain", "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "testlambdaelasticsearchstackCognitoUserPool05D1387E", }, }, "Type": "AWS::Cognito::UserPoolDomain", diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json index 63c0bae3e..227a829bc 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.expected.json @@ -1,6 +1,6 @@ { "Resources": { - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdaelasticsearchkibanaLambdaFunctionServiceRole3AFFEAA2": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -51,7 +51,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testlambdaelasticsearchkibanaLambdaFunction601D26D3": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -95,7 +95,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdaelasticsearchkibanaLambdaFunctionServiceRole3AFFEAA2", "Arn" ] }, @@ -105,7 +105,7 @@ "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", "DOMAIN_ENDPOINT": { "Fn::GetAtt": [ - "ElasticsearchDomain", + "testlambdaelasticsearchkibanaElasticsearchDomain50D5F86E", "DomainEndpoint" ] } @@ -113,7 +113,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdaelasticsearchkibanaLambdaFunctionServiceRole3AFFEAA2" ], "Metadata": { "cfn_nag": { @@ -126,35 +126,102 @@ } } }, - "CognitoUserPool53E37E69": { + "testlambdaelasticsearchkibanaCognitoUserPoolsmsRoleA9BE07AD": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "testlambdaelasticsearchkibanastacktestlambdaelasticsearchkibanaCognitoUserPoolB641EEBB" + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cognito-idp.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "sns-publish" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish" + } + ] + } + } + }, + "testlambdaelasticsearchkibanaCognitoUserPool9537802B": { "Type": "AWS::Cognito::UserPool", "Properties": { - "LambdaConfig": {}, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": { + "ExternalId": "testlambdaelasticsearchkibanastacktestlambdaelasticsearchkibanaCognitoUserPoolB641EEBB", + "SnsCallerArn": { + "Fn::GetAtt": [ + "testlambdaelasticsearchkibanaCognitoUserPoolsmsRoleA9BE07AD", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": { "AdvancedSecurityMode": "ENFORCED" + }, + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}" } } }, - "CognitoUserPoolClient5AB59AE4": { + "testlambdaelasticsearchkibanaCognitoUserPoolClient8F70A2AA": { "Type": "AWS::Cognito::UserPoolClient", "Properties": { "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testlambdaelasticsearchkibanaCognitoUserPool9537802B" } } }, - "CognitoIdentityPool": { + "testlambdaelasticsearchkibanaCognitoIdentityPoolC48068F0": { "Type": "AWS::Cognito::IdentityPool", "Properties": { "AllowUnauthenticatedIdentities": false, "CognitoIdentityProviders": [ { "ClientId": { - "Ref": "CognitoUserPoolClient5AB59AE4" + "Ref": "testlambdaelasticsearchkibanaCognitoUserPoolClient8F70A2AA" }, "ProviderName": { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "testlambdaelasticsearchkibanaCognitoUserPool9537802B", "ProviderName" ] }, @@ -163,19 +230,19 @@ ] } }, - "UserPoolDomain": { + "testlambdaelasticsearchkibanaUserPoolDomainB9BDF063": { "Type": "AWS::Cognito::UserPoolDomain", "Properties": { "Domain": "test-domain1", "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testlambdaelasticsearchkibanaCognitoUserPool9537802B" } }, "DependsOn": [ - "CognitoUserPool53E37E69" + "testlambdaelasticsearchkibanaCognitoUserPool9537802B" ] }, - "CognitoAuthorizedRole14E74FE0": { + "testlambdaelasticsearchkibanaCognitoAuthorizedRole88FAFCFA": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -185,7 +252,7 @@ "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": { - "Ref": "CognitoIdentityPool" + "Ref": "testlambdaelasticsearchkibanaCognitoIdentityPoolC48068F0" } }, "ForAnyValue:StringLike": { @@ -232,23 +299,23 @@ ] } }, - "IdentityPoolRoleMapping": { + "testlambdaelasticsearchkibanaIdentityPoolRoleMappingBD0A239B": { "Type": "AWS::Cognito::IdentityPoolRoleAttachment", "Properties": { "IdentityPoolId": { - "Ref": "CognitoIdentityPool" + "Ref": "testlambdaelasticsearchkibanaCognitoIdentityPoolC48068F0" }, "Roles": { "authenticated": { "Fn::GetAtt": [ - "CognitoAuthorizedRole14E74FE0", + "testlambdaelasticsearchkibanaCognitoAuthorizedRole88FAFCFA", "Arn" ] } } } }, - "CognitoKibanaConfigureRole62CCE76A": { + "testlambdaelasticsearchkibanaCognitoKibanaConfigureRole8F40C1A1": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -265,7 +332,7 @@ } } }, - "CognitoKibanaConfigureRolePolicy76F46A5E": { + "testlambdaelasticsearchkibanaCognitoKibanaConfigureRolePolicyB7090E91": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -289,7 +356,7 @@ "Resource": [ { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "testlambdaelasticsearchkibanaCognitoUserPool9537802B", "Arn" ] }, @@ -307,7 +374,7 @@ }, ":identitypool/", { - "Ref": "CognitoIdentityPool" + "Ref": "testlambdaelasticsearchkibanaCognitoIdentityPoolC48068F0" } ] ] @@ -340,7 +407,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "CognitoKibanaConfigureRole62CCE76A", + "testlambdaelasticsearchkibanaCognitoKibanaConfigureRole8F40C1A1", "Arn" ] } @@ -348,15 +415,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "CognitoKibanaConfigureRolePolicy76F46A5E", + "PolicyName": "testlambdaelasticsearchkibanaCognitoKibanaConfigureRolePolicyB7090E91", "Roles": [ { - "Ref": "CognitoKibanaConfigureRole62CCE76A" + "Ref": "testlambdaelasticsearchkibanaCognitoKibanaConfigureRole8F40C1A1" } ] } }, - "ElasticsearchDomain": { + "testlambdaelasticsearchkibanaElasticsearchDomain50D5F86E": { "Type": "AWS::Elasticsearch::Domain", "Properties": { "AccessPolicies": { @@ -368,13 +435,13 @@ "AWS": [ { "Fn::GetAtt": [ - "CognitoAuthorizedRole14E74FE0", + "testlambdaelasticsearchkibanaCognitoAuthorizedRole88FAFCFA", "Arn" ] }, { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdaelasticsearchkibanaLambdaFunctionServiceRole3AFFEAA2", "Arn" ] } @@ -403,16 +470,16 @@ "CognitoOptions": { "Enabled": true, "IdentityPoolId": { - "Ref": "CognitoIdentityPool" + "Ref": "testlambdaelasticsearchkibanaCognitoIdentityPoolC48068F0" }, "RoleArn": { "Fn::GetAtt": [ - "CognitoKibanaConfigureRole62CCE76A", + "testlambdaelasticsearchkibanaCognitoKibanaConfigureRole8F40C1A1", "Arn" ] }, "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "testlambdaelasticsearchkibanaCognitoUserPool9537802B" } }, "DomainName": "test-domain1", @@ -451,7 +518,7 @@ } } }, - "StatusRedAlarm4CE918C2": { + "testlambdaelasticsearchkibanaStatusRedAlarmCFCDB629": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -464,7 +531,7 @@ "Threshold": 1 } }, - "StatusYellowAlarm2B20F083": { + "testlambdaelasticsearchkibanaStatusYellowAlarm24B9D1CB": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -477,7 +544,7 @@ "Threshold": 1 } }, - "FreeStorageSpaceTooLowAlarm3410CBE2": { + "testlambdaelasticsearchkibanaFreeStorageSpaceTooLowAlarm0B4D4E35": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "LessThanOrEqualToThreshold", @@ -490,7 +557,7 @@ "Threshold": 2000 } }, - "IndexWritesBlockedTooHighAlarm5F7E9A55": { + "testlambdaelasticsearchkibanaIndexWritesBlockedTooHighAlarmB8C0E99C": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -503,7 +570,7 @@ "Threshold": 1 } }, - "AutomatedSnapshotFailureTooHighAlarmA7918D4F": { + "testlambdaelasticsearchkibanaAutomatedSnapshotFailureTooHighAlarm75F2676B": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -516,7 +583,7 @@ "Threshold": 1 } }, - "CPUUtilizationTooHighAlarmA395C469": { + "testlambdaelasticsearchkibanaCPUUtilizationTooHighAlarmF16BA5D9": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -529,7 +596,7 @@ "Threshold": 80 } }, - "JVMMemoryPressureTooHighAlarm303EEA7C": { + "testlambdaelasticsearchkibanaJVMMemoryPressureTooHighAlarm18224533": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -542,7 +609,7 @@ "Threshold": 80 } }, - "MasterCPUUtilizationTooHighAlarm1CE1084B": { + "testlambdaelasticsearchkibanaMasterCPUUtilizationTooHighAlarmE5E5999F": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", @@ -555,7 +622,7 @@ "Threshold": 50 } }, - "MasterJVMMemoryPressureTooHighAlarmBB15F770": { + "testlambdaelasticsearchkibanaMasterJVMMemoryPressureTooHighAlarm297FF1BE": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "ComparisonOperator": "GreaterThanOrEqualToThreshold", diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts index 62ad18f0c..78212c177 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts @@ -48,7 +48,7 @@ test('check domain names', () => { expect(stack).toHaveResource('AWS::Cognito::UserPoolDomain', { Domain: "test-domain", UserPoolId: { - Ref: "CognitoUserPool53E37E69" + Ref: "testlambdaelasticsearchstackCognitoUserPool05D1387E" } }); diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/lib/index.ts index a3154d45c..091d15244 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/lib/index.ts @@ -92,7 +92,7 @@ export class LambdaToS3 extends Construct { super(scope, id); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/package.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/package.json index b920dad95..1e2e3d60c 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-lambda-s3", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,13 +52,14 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -68,9 +69,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/__snapshots__/lambda-s3.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/__snapshots__/lambda-s3.test.js.snap index 95fb268b7..c57a6ec6a 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/__snapshots__/lambda-s3.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/__snapshots__/lambda-s3.test.js.snap @@ -17,10 +17,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -82,7 +82,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -90,7 +90,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -141,7 +141,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -196,10 +196,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -306,10 +306,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -371,7 +371,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -379,7 +379,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -430,7 +430,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -455,10 +455,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -565,10 +565,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -630,7 +630,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -638,7 +638,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -689,7 +689,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -717,10 +717,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -827,10 +827,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -892,7 +892,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -900,7 +900,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -951,7 +951,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -988,10 +988,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -1098,10 +1098,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -1163,7 +1163,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -1171,7 +1171,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -1222,7 +1222,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -1262,10 +1262,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -1372,10 +1372,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -1437,7 +1437,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -1445,7 +1445,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -1496,7 +1496,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -1533,10 +1533,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -1643,10 +1643,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -1708,7 +1708,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -1716,7 +1716,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -1767,7 +1767,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -1807,10 +1807,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, @@ -1917,10 +1917,10 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatos3stackLambdaFunctionDA71B293": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", ], "Metadata": Object { "cfn_nag": Object { @@ -1982,7 +1982,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatos3stackLambdaFunctionServiceRole7E511A8A", "Arn", ], }, @@ -1990,7 +1990,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatos3stackLambdaFunctionServiceRole7E511A8A": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -2041,7 +2041,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -2081,10 +2081,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatos3stackLambdaFunctionServiceRoleDefaultPolicy97EC0F3A", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatos3stackLambdaFunctionServiceRole7E511A8A", }, ], }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/integ.deployFunction.expected.json index 644e9e3c0..b175b693f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/integ.deployFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-s3/test/integ.deployFunction.expected.json @@ -1,87 +1,7 @@ { "Description": "Integration Test for aws-lambda-s3", "Resources": { - "testlambdas3S3LoggingBucketD42FC73D": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - }, - { - "id": "W51", - "reason": "This S3 bucket Bucket does not need a bucket policy" - } - ] - } - } - }, - "testlambdas3S3Bucket179A52E6": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "testlambdas3S3LoggingBucketD42FC73D" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W51", - "reason": "This S3 bucket Bucket does not need a bucket policy" - } - ] - } - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdas3LambdaFunctionServiceRole72E20379": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -132,7 +52,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testlambdas3LambdaFunctionServiceRoleDefaultPolicyB6FC6493": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -173,15 +93,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdas3LambdaFunctionServiceRoleDefaultPolicyB6FC6493", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testlambdas3LambdaFunctionServiceRole72E20379" } ] } }, - "LambdaFunctionBF21E41F": { + "testlambdas3LambdaFunction1B8788C9": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -225,7 +145,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdas3LambdaFunctionServiceRole72E20379", "Arn" ] }, @@ -240,8 +160,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdas3LambdaFunctionServiceRoleDefaultPolicyB6FC6493", + "testlambdas3LambdaFunctionServiceRole72E20379" ], "Metadata": { "cfn_nag": { @@ -253,6 +173,86 @@ ] } } + }, + "testlambdas3S3LoggingBucketD42FC73D": { + "Type": "AWS::S3::Bucket", + "Properties": { + "AccessControl": "LogDeliveryWrite", + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W35", + "reason": "This S3 bucket is used as the access logging bucket for another bucket" + }, + { + "id": "W51", + "reason": "This S3 bucket Bucket does not need a bucket policy" + } + ] + } + } + }, + "testlambdas3S3Bucket179A52E6": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "LoggingConfiguration": { + "DestinationBucketName": { + "Ref": "testlambdas3S3LoggingBucketD42FC73D" + } + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W51", + "reason": "This S3 bucket Bucket does not need a bucket policy" + } + ] + } + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/lib/index.ts index e4364fd4d..d7518d58d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/lib/index.ts @@ -84,7 +84,7 @@ export class LambdaToSns extends Construct { super(scope, id); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/package.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/package.json index 4e3341de9..f68803794 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-lambda-sns", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon SNS topic.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,14 +52,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -69,10 +70,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/__snapshots__/lambda-sns.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/__snapshots__/lambda-sns.test.js.snap index c6788a0ef..fbc40ee73 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/__snapshots__/lambda-sns.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/__snapshots__/lambda-sns.test.js.snap @@ -17,10 +17,62 @@ Object { }, }, "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatosnsstackEncryptionKeyF46E3814": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "EnableKeyRotation": true, + "KeyPolicy": Object { + "Statement": Array [ + Object { + "Action": Array [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource", + ], + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::", + Object { + "Ref": "AWS::AccountId", + }, + ":root", + ], + ], + }, + }, + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::KMS::Key", + "UpdateReplacePolicy": "Retain", + }, + "lambdatosnsstackLambdaFunction84DDA23E": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", ], "Metadata": Object { "cfn_nag": Object { @@ -89,7 +141,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", "Arn", ], }, @@ -97,7 +149,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -148,7 +200,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -162,19 +214,48 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", }, ], }, "Type": "AWS::IAM::Policy", }, - "lambdatosnsstackEncryptionKeyF46E3814": Object { + "lambdatosnsstackSnsTopic6292A14A": Object { + "Properties": Object { + "KmsMasterKeyId": Object { + "Ref": "lambdatosnsstackEncryptionKeyF46E3814", + }, + }, + "Type": "AWS::SNS::Topic", + }, + }, +} +`; + +exports[`Test deployment with imported encryption key 1`] = ` +Object { + "Parameters": Object { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { + "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { + "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { + "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + }, + "Resources": Object { + "importedkey38675D68": Object { "DeletionPolicy": "Retain", "Properties": Object { - "EnableKeyRotation": true, + "EnableKeyRotation": false, "KeyPolicy": Object { "Statement": Array [ Object { @@ -223,39 +304,10 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "lambdatosnsstackSnsTopic6292A14A": Object { - "Properties": Object { - "KmsMasterKeyId": Object { - "Ref": "lambdatosnsstackEncryptionKeyF46E3814", - }, - }, - "Type": "AWS::SNS::Topic", - }, - }, -} -`; - -exports[`Test deployment with imported encryption key 1`] = ` -Object { - "Parameters": Object { - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { - "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { - "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { - "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - }, - "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatosnsstackLambdaFunction84DDA23E": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", ], "Metadata": Object { "cfn_nag": Object { @@ -324,7 +376,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", "Arn", ], }, @@ -332,7 +384,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -383,7 +435,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -397,19 +449,48 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", }, ], }, "Type": "AWS::IAM::Policy", }, - "importedkey38675D68": Object { + "lambdatosnsstackSnsTopic6292A14A": Object { + "Properties": Object { + "KmsMasterKeyId": Object { + "Ref": "importedkey38675D68", + }, + }, + "Type": "AWS::SNS::Topic", + }, + }, +} +`; + +exports[`Test deployment with new Lambda function 1`] = ` +Object { + "Parameters": Object { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { + "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { + "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { + "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatosnsstackEncryptionKeyF46E3814": Object { "DeletionPolicy": "Retain", "Properties": Object { - "EnableKeyRotation": false, + "EnableKeyRotation": true, "KeyPolicy": Object { "Statement": Array [ Object { @@ -458,39 +539,10 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "lambdatosnsstackSnsTopic6292A14A": Object { - "Properties": Object { - "KmsMasterKeyId": Object { - "Ref": "importedkey38675D68", - }, - }, - "Type": "AWS::SNS::Topic", - }, - }, -} -`; - -exports[`Test deployment with new Lambda function 1`] = ` -Object { - "Parameters": Object { - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { - "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { - "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { - "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", - "Type": "String", - }, - }, - "Resources": Object { - "LambdaFunctionBF21E41F": Object { + "lambdatosnsstackLambdaFunction84DDA23E": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", ], "Metadata": Object { "cfn_nag": Object { @@ -559,7 +611,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", "Arn", ], }, @@ -567,7 +619,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -618,7 +670,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -632,67 +684,15 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "lambdatosnsstackLambdaFunctionServiceRoleDefaultPolicy787D809F", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "lambdatosnsstackLambdaFunctionServiceRole55BFEAA9", }, ], }, "Type": "AWS::IAM::Policy", }, - "lambdatosnsstackEncryptionKeyF46E3814": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "EnableKeyRotation": true, - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": Array [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Retain", - }, "lambdatosnsstackSnsTopic6292A14A": Object { "Properties": Object { "KmsMasterKeyId": Object { diff --git a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/integ.deployFunction.expected.json index 8894271f5..89d175225 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/integ.deployFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-lambda-sns/test/integ.deployFunction.expected.json @@ -1,67 +1,7 @@ { "Description": "Integration Test for aws-lambda-sns", "Resources": { - "testlambdasnsEncryptionKey57F4E220": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "EnableKeyRotation": true - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "testlambdasnsSnsTopic57DFED98": { - "Type": "AWS::SNS::Topic", - "Properties": { - "KmsMasterKeyId": { - "Ref": "testlambdasnsEncryptionKey57F4E220" - } - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testlambdasnsLambdaFunctionServiceRole9C412F74": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -112,7 +52,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testlambdasnsLambdaFunctionServiceRoleDefaultPolicyBB1D55CB": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -127,15 +67,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testlambdasnsLambdaFunctionServiceRoleDefaultPolicyBB1D55CB", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testlambdasnsLambdaFunctionServiceRole9C412F74" } ] } }, - "LambdaFunctionBF21E41F": { + "testlambdasnsLambdaFunctionD8BC8ABA": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -179,7 +119,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testlambdasnsLambdaFunctionServiceRole9C412F74", "Arn" ] }, @@ -200,8 +140,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testlambdasnsLambdaFunctionServiceRoleDefaultPolicyBB1D55CB", + "testlambdasnsLambdaFunctionServiceRole9C412F74" ], "Metadata": { "cfn_nag": { @@ -213,6 +153,66 @@ ] } } + }, + "testlambdasnsEncryptionKey57F4E220": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testlambdasnsSnsTopic57DFED98": { + "Type": "AWS::SNS::Topic", + "Properties": { + "KmsMasterKeyId": { + "Ref": "testlambdasnsEncryptionKey57F4E220" + } + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/lib/index.ts index 7847c2feb..5931974ee 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/lib/index.ts @@ -13,8 +13,8 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; -import * as iam from '@aws-cdk/aws-iam'; import { Construct, Stack } from '@aws-cdk/core'; +import * as iam from '@aws-cdk/aws-iam'; import * as defaults from '@aws-solutions-konstruk/core'; import { S3EventSourceProps, S3EventSource } from '@aws-cdk/aws-lambda-event-sources'; @@ -77,7 +77,7 @@ export class S3ToLambda extends Construct { private fn: lambda.Function; private bucket: s3.Bucket; /** - * @summary Constructs a new instance of the IotToLambda class. + * @summary Constructs a new instance of the S3ToLambda class. * @param {cdk.App} scope - represents the scope for all the resources. * @param {string} id - this is a a scope-unique id. * @param {S3ToLambdaProps} props - user provided props for the construct @@ -87,13 +87,13 @@ export class S3ToLambda extends Construct { constructor(scope: Construct, id: string, props: S3ToLambdaProps) { super(scope, id); - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps }); - this.bucket = defaults.buildS3Bucket(scope, { + this.bucket = defaults.buildS3Bucket(this, { deployBucket: props.deployBucket, existingBucketObj: props.existingBucketObj, bucketProps: props.bucketProps @@ -103,10 +103,10 @@ export class S3ToLambda extends Construct { this.fn.addEventSource(new S3EventSource(this.bucket, defaults.S3EventSourceProps(props.s3EventSourceProps))); - this.addCfnNagSuppress(scope); + this.addCfnNagSuppress(); } - private addCfnNagSuppress(scope: Construct) { + private addCfnNagSuppress() { // Extract the CfnBucket from the s3Bucket const s3BucketResource = this.bucket.node.findChild('Resource') as s3.CfnBucket; @@ -119,7 +119,7 @@ export class S3ToLambda extends Construct { } }; - const root = Stack.of(scope); + const root = Stack.of(this); const logicalId = 'BucketNotificationsHandler050a0587b7544547bf325f094a3db834'; const notificationsResourceHandler = root.node.tryFindChild(logicalId) as lambda.Function; const notificationsResourceHandlerRoleRole = notificationsResourceHandler.node.findChild('Role') as iam.Role; diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/package.json index b02028928..a0d85aad9 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-s3-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS S3 to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/aws-s3-notifications": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/aws-s3-notifications": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-s3-notifications": "~1.25.0" + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-s3-notifications": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap index 5e7815b1c..407a3d45f 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap @@ -38,9 +38,9 @@ Object { // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies const s3 = new (require('aws-sdk').S3)(); // eslint-disable-next-line @typescript-eslint/no-require-imports - const https = require(\\"https\\"); + const https = require('https'); // eslint-disable-next-line @typescript-eslint/no-require-imports - const url = require(\\"url\\"); + const url = require('url'); log(JSON.stringify(event, undefined, 2)); const props = event.ResourceProperties; if (event.RequestType === 'Delete') { @@ -48,15 +48,15 @@ Object { } const req = { Bucket: props.BucketName, - NotificationConfiguration: props.NotificationConfiguration + NotificationConfiguration: props.NotificationConfiguration, }; return s3.putBucketNotificationConfiguration(req, (err, data) => { log({ err, data }); if (err) { - return submitResponse(\\"FAILED\\", err.message + \`\\\\nMore information in CloudWatch Log Stream: \${context.logStreamName}\`); + return submitResponse('FAILED', err.message + \`\\\\nMore information in CloudWatch Log Stream: \${context.logStreamName}\`); } else { - return submitResponse(\\"SUCCESS\\"); + return submitResponse('SUCCESS'); } }); function log(obj) { @@ -68,7 +68,7 @@ Object { function submitResponse(responseStatus, reason) { const responseBody = JSON.stringify({ Status: responseStatus, - Reason: reason || \\"See the details in CloudWatch Log Stream: \\" + context.logStreamName, + Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName, PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId, StackId: event.StackId, RequestId: event.RequestId, @@ -81,17 +81,17 @@ Object { hostname: parsedUrl.hostname, port: 443, path: parsedUrl.path, - method: \\"PUT\\", + method: 'PUT', headers: { - \\"content-type\\": \\"\\", - \\"content-length\\": responseBody.length - } + 'content-type': '', + 'content-length': responseBody.length, + }, }; const request = https.request(options, (r) => { log({ statusCode: r.statusCode, statusMessage: r.statusMessage }); context.done(); }); - request.on(\\"error\\", (error) => { + request.on('error', (error) => { log({ sendError: error }); context.done(); }); @@ -175,12 +175,12 @@ Object { }, "Type": "AWS::IAM::Policy", }, - "LambdaFunctionAllowBucketNotificationsFromS3Bucket25B4F189": Object { + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdaS3Bucket9453157137836A69": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn", ], }, @@ -190,16 +190,16 @@ Object { }, "SourceArn": Object { "Fn::GetAtt": Array [ - "S3Bucket07682993", + "tests3lambdaS3BucketBE7C1B8E", "Arn", ], }, }, "Type": "AWS::Lambda::Permission", }, - "LambdaFunctionBF21E41F": Object { + "tests3lambdaLambdaFunctionB56B7023": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "tests3lambdaLambdaFunctionServiceRoleA74F4427", ], "Metadata": Object { "cfn_nag": Object { @@ -258,7 +258,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "tests3lambdaLambdaFunctionServiceRoleA74F4427", "Arn", ], }, @@ -266,7 +266,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "tests3lambdaLambdaFunctionServiceRoleA74F4427": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -317,7 +317,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "S3Bucket07682993": Object { + "tests3lambdaS3BucketBE7C1B8E": Object { "DeletionPolicy": "Retain", "Metadata": Object { "cfn_nag": Object { @@ -341,7 +341,7 @@ Object { }, "LoggingConfiguration": Object { "DestinationBucketName": Object { - "Ref": "S3LoggingBucket800A2B27", + "Ref": "tests3lambdaS3LoggingBucket0C3BBFDC", }, }, "PublicAccessBlockConfiguration": Object { @@ -357,13 +357,13 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, - "S3BucketNotifications58B5AD06": Object { + "tests3lambdaS3BucketNotifications1943E9B3": Object { "DependsOn": Array [ - "LambdaFunctionAllowBucketNotificationsFromS3Bucket25B4F189", + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdaS3Bucket9453157137836A69", ], "Properties": Object { "BucketName": Object { - "Ref": "S3Bucket07682993", + "Ref": "tests3lambdaS3BucketBE7C1B8E", }, "NotificationConfiguration": Object { "LambdaFunctionConfigurations": Array [ @@ -373,7 +373,7 @@ Object { ], "LambdaFunctionArn": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn", ], }, @@ -389,7 +389,7 @@ Object { }, "Type": "Custom::S3BucketNotifications", }, - "S3LoggingBucket800A2B27": Object { + "tests3lambdaS3LoggingBucket0C3BBFDC": Object { "DeletionPolicy": "Retain", "Metadata": Object { "cfn_nag": Object { diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json index f5a11688e..a2201787e 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json @@ -100,7 +100,7 @@ ], "LambdaFunctionArn": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn" ] } @@ -109,10 +109,10 @@ } }, "DependsOn": [ - "LambdaFunctionAllowBucketNotificationsFromtests3lambdastackS3BucketAA5BB5A99E8B1157" + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdaexistingbucketstackS3BucketA1F8245606EA6713" ] }, - "LambdaFunctionServiceRole0C4CDE0B": { + "tests3lambdaLambdaFunctionServiceRoleA74F4427": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -163,7 +163,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "tests3lambdaLambdaFunctionB56B7023": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -207,7 +207,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "tests3lambdaLambdaFunctionServiceRoleA74F4427", "Arn" ] }, @@ -219,7 +219,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "tests3lambdaLambdaFunctionServiceRoleA74F4427" ], "Metadata": { "cfn_nag": { @@ -232,13 +232,13 @@ } } }, - "LambdaFunctionAllowBucketNotificationsFromtests3lambdastackS3BucketAA5BB5A99E8B1157": { + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdaexistingbucketstackS3BucketA1F8245606EA6713": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn" ] }, @@ -321,7 +321,7 @@ "Properties": { "Description": "AWS CloudFormation handler for \"Custom::S3BucketNotifications\" resources (@aws-cdk/aws-s3)", "Code": { - "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require(\"https\");\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require(\"url\");\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse(\"FAILED\", err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse(\"SUCCESS\");\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || \"See the details in CloudWatch Log Stream: \" + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: \"PUT\",\n headers: {\n \"content-type\": \"\",\n \"content-length\": responseBody.length\n }\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on(\"error\", (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" + "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" }, "Handler": "index.handler", "Role": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.ts b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.ts index fb126fa64..d4cfa5665 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.existing-s3-bucket.ts @@ -20,7 +20,7 @@ import * as defaults from '@aws-solutions-konstruk/core'; const app = new App(); // Empty arguments -const stack = new Stack(app, 'test-s3-lambda-stack'); +const stack = new Stack(app, 'test-s3-lambda-existing-bucket-stack'); const myBucket: s3.Bucket = defaults.buildS3Bucket(stack, {}); diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.expected.json index 4d1829de0..0a6f102aa 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.expected.json @@ -1,6 +1,6 @@ { "Resources": { - "LambdaFunctionServiceRole0C4CDE0B": { + "tests3lambdaLambdaFunctionServiceRoleA74F4427": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -51,7 +51,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "tests3lambdaLambdaFunctionB56B7023": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -95,7 +95,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "tests3lambdaLambdaFunctionServiceRoleA74F4427", "Arn" ] }, @@ -107,7 +107,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "tests3lambdaLambdaFunctionServiceRoleA74F4427" ], "Metadata": { "cfn_nag": { @@ -120,13 +120,13 @@ } } }, - "LambdaFunctionAllowBucketNotificationsFromtests3lambdastackS3BucketAA5BB5A99E8B1157": { + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdanewbucketstacktests3lambdaS3Bucket7441CD5B3462BBCF": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn" ] }, @@ -136,13 +136,13 @@ }, "SourceArn": { "Fn::GetAtt": [ - "S3Bucket07682993", + "tests3lambdaS3BucketBE7C1B8E", "Arn" ] } } }, - "S3LoggingBucket800A2B27": { + "tests3lambdaS3LoggingBucket0C3BBFDC": { "Type": "AWS::S3::Bucket", "Properties": { "AccessControl": "LogDeliveryWrite", @@ -182,7 +182,7 @@ } } }, - "S3Bucket07682993": { + "tests3lambdaS3BucketBE7C1B8E": { "Type": "AWS::S3::Bucket", "Properties": { "BucketEncryption": { @@ -196,7 +196,7 @@ }, "LoggingConfiguration": { "DestinationBucketName": { - "Ref": "S3LoggingBucket800A2B27" + "Ref": "tests3lambdaS3LoggingBucket0C3BBFDC" } }, "PublicAccessBlockConfiguration": { @@ -222,7 +222,7 @@ } } }, - "S3BucketNotifications58B5AD06": { + "tests3lambdaS3BucketNotifications1943E9B3": { "Type": "Custom::S3BucketNotifications", "Properties": { "ServiceToken": { @@ -232,7 +232,7 @@ ] }, "BucketName": { - "Ref": "S3Bucket07682993" + "Ref": "tests3lambdaS3BucketBE7C1B8E" }, "NotificationConfiguration": { "LambdaFunctionConfigurations": [ @@ -242,7 +242,7 @@ ], "LambdaFunctionArn": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "tests3lambdaLambdaFunctionB56B7023", "Arn" ] } @@ -251,7 +251,7 @@ } }, "DependsOn": [ - "LambdaFunctionAllowBucketNotificationsFromtests3lambdastackS3BucketAA5BB5A99E8B1157" + "tests3lambdaLambdaFunctionAllowBucketNotificationsFromtests3lambdanewbucketstacktests3lambdaS3Bucket7441CD5B3462BBCF" ] }, "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC": { @@ -321,7 +321,7 @@ "Properties": { "Description": "AWS CloudFormation handler for \"Custom::S3BucketNotifications\" resources (@aws-cdk/aws-s3)", "Code": { - "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require(\"https\");\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require(\"url\");\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse(\"FAILED\", err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse(\"SUCCESS\");\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || \"See the details in CloudWatch Log Stream: \" + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: \"PUT\",\n headers: {\n \"content-type\": \"\",\n \"content-length\": responseBody.length\n }\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on(\"error\", (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" + "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" }, "Handler": "index.handler", "Role": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.ts index b32792b34..ed229dd35 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-s3-lambda/test/integ.no-arguments.ts @@ -18,7 +18,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; const app = new App(); // Empty arguments -const stack = new Stack(app, 'test-s3-lambda-stack'); +const stack = new Stack(app, 'test-s3-lambda-new-bucket-stack'); const props: S3ToLambdaProps = { deployLambda: true, diff --git a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/lib/index.ts index 970706eec..8d78984e5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/lib/index.ts @@ -84,7 +84,7 @@ export class SnsToLambda extends Construct { super(scope, id); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps diff --git a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/package.json index 15812c402..2d319da18 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-sns-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK Constructs for AWS SNS to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-kms": "~1.25.0" + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-kms": "~1.40.0", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/__snapshots__/sns-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/__snapshots__/sns-lambda.test.js.snap index bb96c684a..c4f692966 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/__snapshots__/sns-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/__snapshots__/sns-lambda.test.js.snap @@ -17,12 +17,64 @@ Object { }, }, "Resources": Object { - "LambdaFunctionAllowInvoketestsnslambdaSnsTopicEB0543A084BF6FA6": Object { + "testsnslambdaEncryptionKeyDDDF040B": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "EnableKeyRotation": true, + "KeyPolicy": Object { + "Statement": Array [ + Object { + "Action": Array [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource", + ], + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::", + Object { + "Ref": "AWS::AccountId", + }, + ":root", + ], + ], + }, + }, + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::KMS::Key", + "UpdateReplacePolicy": "Retain", + }, + "testsnslambdaLambdaFunctionAllowInvoketestsnslambdaSnsTopicEB0543A09281910D": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testsnslambdaLambdaFunctionEE9A249B", "Arn", ], }, @@ -33,9 +85,9 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "LambdaFunctionBF21E41F": Object { + "testsnslambdaLambdaFunctionEE9A249B": Object { "DependsOn": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsnslambdaLambdaFunctionServiceRole23794781", ], "Metadata": Object { "cfn_nag": Object { @@ -94,7 +146,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsnslambdaLambdaFunctionServiceRole23794781", "Arn", ], }, @@ -102,7 +154,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testsnslambdaLambdaFunctionServiceRole23794781": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -153,11 +205,11 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionSnsTopic70134CE0": Object { + "testsnslambdaLambdaFunctionSnsTopic9C14F333": Object { "Properties": Object { "Endpoint": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "testsnslambdaLambdaFunctionEE9A249B", "Arn", ], }, @@ -168,58 +220,6 @@ Object { }, "Type": "AWS::SNS::Subscription", }, - "testsnslambdaEncryptionKeyDDDF040B": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "EnableKeyRotation": true, - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": Array [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Retain", - }, "testsnslambdaSnsTopic52CA159E": Object { "Properties": Object { "KmsMasterKeyId": Object { diff --git a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/integ.no-arguments.expected.json index 0dd935987..18cccb279 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-sns-lambda/test/integ.no-arguments.expected.json @@ -1,67 +1,7 @@ { "Description": "Integration Test for aws-sns-lambda", "Resources": { - "testsnslambdaEncryptionKeyDDDF040B": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "EnableKeyRotation": true - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "testsnslambdaSnsTopic52CA159E": { - "Type": "AWS::SNS::Topic", - "Properties": { - "KmsMasterKeyId": { - "Ref": "testsnslambdaEncryptionKeyDDDF040B" - } - } - }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testsnslambdaLambdaFunctionServiceRole23794781": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -112,7 +52,7 @@ ] } }, - "LambdaFunctionBF21E41F": { + "testsnslambdaLambdaFunctionEE9A249B": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -156,7 +96,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsnslambdaLambdaFunctionServiceRole23794781", "Arn" ] }, @@ -168,7 +108,7 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRole0C4CDE0B" + "testsnslambdaLambdaFunctionServiceRole23794781" ], "Metadata": { "cfn_nag": { @@ -181,13 +121,13 @@ } } }, - "LambdaFunctionAllowInvoketestsnslambdaSnsTopic02988CE1827B8D82": { + "testsnslambdaLambdaFunctionAllowInvoketestsnslambdaSnsTopic02988CE17E59B06E": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testsnslambdaLambdaFunctionEE9A249B", "Arn" ] }, @@ -197,7 +137,7 @@ } } }, - "LambdaFunctionSnsTopic70134CE0": { + "testsnslambdaLambdaFunctionSnsTopic9C14F333": { "Type": "AWS::SNS::Subscription", "Properties": { "Protocol": "lambda", @@ -206,11 +146,71 @@ }, "Endpoint": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "testsnslambdaLambdaFunctionEE9A249B", "Arn" ] } } + }, + "testsnslambdaEncryptionKeyDDDF040B": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testsnslambdaSnsTopic52CA159E": { + "Type": "AWS::SNS::Topic", + "Properties": { + "KmsMasterKeyId": { + "Ref": "testsnslambdaEncryptionKeyDDDF040B" + } + } } }, "Parameters": { diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/README.md b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/README.md index 250527ad9..91330d7b9 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/README.md +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/README.md @@ -36,9 +36,7 @@ new SqsToLambda(stack, 'SqsToLambdaPattern', { runtime: lambda.Runtime.NODEJS_10_X, handler: 'index.handler', code: lambda.Code.asset(`${__dirname}/lambda`) - }, - deployDeadLetterQueue: true, - maxReceiveCount: 15 + } }); ``` @@ -64,8 +62,8 @@ _Parameters_ |lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user-provided props to override the default props for the Lambda function.| |queueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided props to override the default props for the SQS queue.| |encryptionKeyProps?|[`kms.KeyProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kms.KeyProps.html)|Optional user-provided props to override the default props for the KMS encryption key.| -|deployDeadLetterQueue|`boolean`|Whether to create a secondary queue to be used as a dead letter queue.| -|maxReceiveCount|`number`|The number of times a message can be unsuccesfully dequeued before being moved to the dead letter queue.| +|deployDeadLetterQueue?|`boolean`|Whether to create a secondary queue to be used as a dead letter queue. Defaults to true.| +|maxReceiveCount?|`number`|The number of times a message can be unsuccesfully dequeued before being moved to the dead letter queue. Defaults to 15.| ## Pattern Properties diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/lib/index.ts index 5dbac146a..96342ac68 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/lib/index.ts @@ -59,15 +59,15 @@ export interface SqsToLambdaProps { /** * Whether to deploy a secondary queue to be used as a dead letter queue. * - * @default - required field. + * @default - true. */ - readonly deployDeadLetterQueue: boolean, + readonly deployDeadLetterQueue?: boolean, /** * The number of times a message can be unsuccesfully dequeued before being moved to the dead-letter queue. * - * @default - required field. + * @default - required field if deployDeadLetterQueue=true. */ - readonly maxReceiveCount: number + readonly maxReceiveCount?: number } /** @@ -91,10 +91,10 @@ export class SqsToLambda extends Construct { super(scope, id); // Setup the encryption key - this.encryptionKey = defaults.buildEncryptionKey(scope, props.encryptionKeyProps); + this.encryptionKey = defaults.buildEncryptionKey(this, props.encryptionKeyProps); // Setup the Lambda function - this.fn = defaults.buildLambdaFunction(scope, { + this.fn = defaults.buildLambdaFunction(this, { deployLambda: props.deployLambda, existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps @@ -102,8 +102,8 @@ export class SqsToLambda extends Construct { // Setup the dead letter queue, if applicable let dlqi: sqs.DeadLetterQueue | undefined; - if (props.deployDeadLetterQueue) { - const dlq: sqs.Queue = defaults.buildQueue(scope, 'deadLetterQueue', { + if (props.deployDeadLetterQueue || props.deployDeadLetterQueue === undefined) { + const dlq: sqs.Queue = defaults.buildQueue(this, 'deadLetterQueue', { encryptionKey: this.encryptionKey, queueProps: props.queueProps }); @@ -114,7 +114,7 @@ export class SqsToLambda extends Construct { } // Setup the queue - this.queue = defaults.buildQueue(scope, 'queue', { + this.queue = defaults.buildQueue(this, 'queue', { encryptionKey: this.encryptionKey, queueProps: props.queueProps, deadLetterQueue: dlqi diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/package.json b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/package.json index 78cffbe9b..c424739a3 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/package.json +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-sqs-lambda", - "version": "0.8.0", + "version": "0.8.1", "description": "CDK constructs for defining an interaction between an Amazon SQS queue and an AWS Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,15 +52,16 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,11 +71,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap index 02aae6d9a..9d6935a2d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap @@ -17,71 +17,6 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "EnableKeyRotation": true, - "KeyPolicy": Object { - "Statement": Array [ - Object { - "Action": Array [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - "Resource": "*", - }, - Object { - "Action": "kms:Decrypt", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "ExistingLambdaFunctionServiceRole7CC6DE65", - "Arn", - ], - }, - }, - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::KMS::Key", - "UpdateReplacePolicy": "Retain", - }, "ExistingLambdaFunctionF606C520": Object { "DependsOn": Array [ "ExistingLambdaFunctionServiceRoleDefaultPolicy2431D213", @@ -183,7 +118,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "testapigatewaylambdaqueue1FFAE03C", "Arn", ], }, @@ -193,7 +128,7 @@ Object { "Effect": "Allow", "Resource": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testapigatewaylambdaEncryptionKey06FC467F", "Arn", ], }, @@ -210,11 +145,11 @@ Object { }, "Type": "AWS::IAM::Policy", }, - "ExistingLambdaFunctionSqsEventSourcequeue85681C04": Object { + "ExistingLambdaFunctionSqsEventSourcetestapigatewaylambdaqueueFD30FF33BE4927D4": Object { "Properties": Object { "EventSourceArn": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "testapigatewaylambdaqueue1FFAE03C", "Arn", ], }, @@ -224,11 +159,76 @@ Object { }, "Type": "AWS::Lambda::EventSourceMapping", }, - "queue276F7297": Object { + "testapigatewaylambdaEncryptionKey06FC467F": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "EnableKeyRotation": true, + "KeyPolicy": Object { + "Statement": Array [ + Object { + "Action": Array [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource", + ], + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::", + Object { + "Ref": "AWS::AccountId", + }, + ":root", + ], + ], + }, + }, + "Resource": "*", + }, + Object { + "Action": "kms:Decrypt", + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::GetAtt": Array [ + "ExistingLambdaFunctionServiceRole7CC6DE65", + "Arn", + ], + }, + }, + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::KMS::Key", + "UpdateReplacePolicy": "Retain", + }, + "testapigatewaylambdaqueue1FFAE03C": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testapigatewaylambdaEncryptionKey06FC467F", "Arn", ], }, @@ -256,7 +256,7 @@ Object { }, }, "Resources": Object { - "EncryptionKey1B843E66": Object { + "testsqslambdaEncryptionKey317A2F03": Object { "DeletionPolicy": "Retain", "Properties": Object { "EnableKeyRotation": true, @@ -307,7 +307,7 @@ Object { "Principal": Object { "AWS": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsqslambdaLambdaFunctionServiceRoleF623B438", "Arn", ], }, @@ -321,10 +321,10 @@ Object { "Type": "AWS::KMS::Key", "UpdateReplacePolicy": "Retain", }, - "LambdaFunctionBF21E41F": Object { + "testsqslambdaLambdaFunction58720146": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C", + "testsqslambdaLambdaFunctionServiceRoleF623B438", ], "Metadata": Object { "cfn_nag": Object { @@ -383,7 +383,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsqslambdaLambdaFunctionServiceRoleF623B438", "Arn", ], }, @@ -391,7 +391,49 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "testsqslambdaqueue601203B8", + "Arn", + ], + }, + }, + Object { + "Action": "kms:Decrypt", + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "testsqslambdaEncryptionKey317A2F03", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C", + "Roles": Array [ + Object { + "Ref": "testsqslambdaLambdaFunctionServiceRoleF623B438", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testsqslambdaLambdaFunctionServiceRoleF623B438": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -442,85 +484,43 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", - "sqs:GetQueueUrl", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "queue276F7297", - "Arn", - ], - }, - }, - Object { - "Action": "kms:Decrypt", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "Roles": Array [ - Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "LambdaFunctionSqsEventSourcequeue7A15E0AF": Object { + "testsqslambdaLambdaFunctionSqsEventSourcetestsqslambdaqueue583E2E6CB891E0FC": Object { "Properties": Object { "EventSourceArn": Object { "Fn::GetAtt": Array [ - "queue276F7297", + "testsqslambdaqueue601203B8", "Arn", ], }, "FunctionName": Object { - "Ref": "LambdaFunctionBF21E41F", + "Ref": "testsqslambdaLambdaFunction58720146", }, }, "Type": "AWS::Lambda::EventSourceMapping", }, - "deadLetterQueue3F848E28": Object { + "testsqslambdadeadLetterQueue85BDB0A3": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn", ], }, }, "Type": "AWS::SQS::Queue", }, - "queue276F7297": Object { + "testsqslambdaqueue601203B8": Object { "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn", ], }, "RedrivePolicy": Object { "deadLetterTargetArn": Object { "Fn::GetAtt": Array [ - "deadLetterQueue3F848E28", + "testsqslambdadeadLetterQueue85BDB0A3", "Arn", ], }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.deployFunction.expected.json index de6b099dc..790d01994 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.deployFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.deployFunction.expected.json @@ -1,7 +1,7 @@ { "Description": "Integration Test for aws-sqs-lambda", "Resources": { - "EncryptionKey1B843E66": { + "testsqslambdaEncryptionKey317A2F03": { "Type": "AWS::KMS::Key", "Properties": { "KeyPolicy": { @@ -51,7 +51,7 @@ "Principal": { "AWS": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsqslambdaLambdaFunctionServiceRoleF623B438", "Arn" ] } @@ -66,7 +66,7 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "LambdaFunctionServiceRole0C4CDE0B": { + "testsqslambdaLambdaFunctionServiceRoleF623B438": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -117,7 +117,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -133,7 +133,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testsqslambdaqueue601203B8", "Arn" ] } @@ -143,7 +143,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] } @@ -151,15 +151,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "testsqslambdaLambdaFunctionServiceRoleF623B438" } ] } }, - "LambdaFunctionBF21E41F": { + "testsqslambdaLambdaFunction58720146": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -203,7 +203,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "testsqslambdaLambdaFunctionServiceRoleF623B438", "Arn" ] }, @@ -215,8 +215,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "testsqslambdaLambdaFunctionServiceRoleDefaultPolicy380B065C", + "testsqslambdaLambdaFunctionServiceRoleF623B438" ], "Metadata": { "cfn_nag": { @@ -229,44 +229,44 @@ } } }, - "LambdaFunctionSqsEventSourcetestsqslambdaqueue583E2E6C926C265C": { + "testsqslambdaLambdaFunctionSqsEventSourcetestsqslambdaqueue0C64355314A98EF1": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "EventSourceArn": { "Fn::GetAtt": [ - "queue276F7297", + "testsqslambdaqueue601203B8", "Arn" ] }, "FunctionName": { - "Ref": "LambdaFunctionBF21E41F" + "Ref": "testsqslambdaLambdaFunction58720146" } } }, - "deadLetterQueue3F848E28": { + "testsqslambdadeadLetterQueue85BDB0A3": { "Type": "AWS::SQS::Queue", "Properties": { "KmsMasterKeyId": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] } } }, - "queue276F7297": { + "testsqslambdaqueue601203B8": { "Type": "AWS::SQS::Queue", "Properties": { "KmsMasterKeyId": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] }, "RedrivePolicy": { "deadLetterTargetArn": { "Fn::GetAtt": [ - "deadLetterQueue3F848E28", + "testsqslambdadeadLetterQueue85BDB0A3", "Arn" ] }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.existingFunction.expected.json b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.existingFunction.expected.json index 2531f650d..63114433d 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.existingFunction.expected.json +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/integ.existingFunction.expected.json @@ -68,7 +68,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "queue276F7297", + "testsqslambdaqueue601203B8", "Arn" ] } @@ -78,7 +78,7 @@ "Effect": "Allow", "Resource": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] } @@ -164,12 +164,12 @@ } } }, - "LambdaFunctionSqsEventSourcetestsqslambdaqueue583E2E6C926C265C": { + "LambdaFunctionSqsEventSourcetestsqslambdaqueue0C6435537BE28DB1": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { "EventSourceArn": { "Fn::GetAtt": [ - "queue276F7297", + "testsqslambdaqueue601203B8", "Arn" ] }, @@ -178,7 +178,7 @@ } } }, - "EncryptionKey1B843E66": { + "testsqslambdaEncryptionKey317A2F03": { "Type": "AWS::KMS::Key", "Properties": { "KeyPolicy": { @@ -243,30 +243,30 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "deadLetterQueue3F848E28": { + "testsqslambdadeadLetterQueue85BDB0A3": { "Type": "AWS::SQS::Queue", "Properties": { "KmsMasterKeyId": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] } } }, - "queue276F7297": { + "testsqslambdaqueue601203B8": { "Type": "AWS::SQS::Queue", "Properties": { "KmsMasterKeyId": { "Fn::GetAtt": [ - "EncryptionKey1B843E66", + "testsqslambdaEncryptionKey317A2F03", "Arn" ] }, "RedrivePolicy": { "deadLetterTargetArn": { "Fn::GetAtt": [ - "deadLetterQueue3F848E28", + "testsqslambdadeadLetterQueue85BDB0A3", "Arn" ] }, diff --git a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/test.sqs-lambda.test.ts b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/test.sqs-lambda.test.ts index a83f2945e..171bc25b5 100644 --- a/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/test.sqs-lambda.test.ts +++ b/source/patterns/@aws-solutions-konstruk/aws-sqs-lambda/test/test.sqs-lambda.test.ts @@ -31,11 +31,7 @@ test('Pattern deployment w/ new Lambda function and default props', () => { runtime: lambda.Runtime.NODEJS_10_X, handler: 'index.handler', code: lambda.Code.asset(`${__dirname}/lambda`) - }, - deployDeadLetterQueue: true, - maxReceiveCount: 15, - queueProps: {}, - encryptionKeyProps: {}, + } }; new SqsToLambda(stack, 'test-sqs-lambda', props); // Assertion 1 diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-defaults.ts b/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-defaults.ts index 03340c9eb..c2a490e4b 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-defaults.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-defaults.ts @@ -13,57 +13,66 @@ import * as api from '@aws-cdk/aws-apigateway'; import * as lambda from '@aws-cdk/aws-lambda'; +import { LogGroup } from '@aws-cdk/aws-logs'; -export function DefaultGlobalLambdaRestApiProps(_existingLambdaObj: lambda.Function) { +/** + * Private function to configure an api.RestApiProps + * @param scope - the construct to which the RestApi should be attached to. + * @param _endpointType - endpoint type for Api Gateway e.g. Regional, Global, Private + * @param _logGroup - CW Log group for Api Gateway access logging + */ +function DefaultRestApiProps(_endpointType: api.EndpointType[], _logGroup: LogGroup): api.RestApiProps { + return { + endpointTypes: _endpointType, + cloudWatchRole: false, + // Configure API Gateway Access logging + deployOptions: { + accessLogDestination: new api.LogGroupLogDestination(_logGroup), + accessLogFormat: api.AccessLogFormat.jsonWithStandardFields(), + loggingLevel: api.MethodLoggingLevel.INFO, + dataTraceEnabled: true + }, + defaultMethodOptions: { + authorizationType: api.AuthorizationType.IAM + } + + } as api.RestApiProps; +} + +/** + * Provides the default set of properties for Edge/Global Lambda backed RestApi + * @param scope - the construct to which the RestApi should be attached to. + * @param _endpointType - endpoint type for Api Gateway e.g. Regional, Global, Private + * @param _logGroup - CW Log group for Api Gateway access logging + */ +export function DefaultGlobalLambdaRestApiProps(_existingLambdaObj: lambda.Function, _logGroup: LogGroup) { const defaultGatewayProps: api.LambdaRestApiProps = { handler: _existingLambdaObj, - options: { - endpointTypes: [api.EndpointType.EDGE], - cloudWatchRole: false, - // Configure API Gateway Execution logging - deployOptions: { - loggingLevel: api.MethodLoggingLevel.INFO, - dataTraceEnabled: true - }, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.IAM - } - } + options: DefaultRestApiProps([api.EndpointType.EDGE], _logGroup) }; return defaultGatewayProps; } -export function DefaultRegionalLambdaRestApiProps(_existingLambdaObj: lambda.Function) { +/** + * Provides the default set of properties for Regional Lambda backed RestApi + * @param scope - the construct to which the RestApi should be attached to. + * @param _endpointType - endpoint type for Api Gateway e.g. Regional, Global, Private + * @param _logGroup - CW Log group for Api Gateway access logging + */ +export function DefaultRegionalLambdaRestApiProps(_existingLambdaObj: lambda.Function, _logGroup: LogGroup) { const defaultGatewayProps: api.LambdaRestApiProps = { handler: _existingLambdaObj, - options: { - endpointTypes: [api.EndpointType.REGIONAL], - cloudWatchRole: false, - // Configure API Gateway Execution logging - deployOptions: { - loggingLevel: api.MethodLoggingLevel.INFO, - dataTraceEnabled: true - }, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.IAM - } - } + options: DefaultRestApiProps([api.EndpointType.REGIONAL], _logGroup) }; return defaultGatewayProps; } -export function DefaultGlobalApiProps() { - const defaultGatewayProps: api.RestApiProps = { - endpointTypes: [api.EndpointType.EDGE], - cloudWatchRole: false, - // Configure API Gateway Execution logging - deployOptions: { - loggingLevel: api.MethodLoggingLevel.INFO, - dataTraceEnabled: true - }, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.IAM - } - }; - return defaultGatewayProps; +/** + * Provides the default set of properties for Edge/Global RestApi + * @param scope - the construct to which the RestApi should be attached to. + * @param _endpointType - endpoint type for Api Gateway e.g. Regional, Global, Private + * @param _logGroup - CW Log group for Api Gateway access logging + */ +export function DefaultGlobalRestApiProps(_logGroup: LogGroup) { + return DefaultRestApiProps([api.EndpointType.EDGE], _logGroup); } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-helper.ts index bb5fc0c1c..75c088956 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/apigateway-helper.ts @@ -21,63 +21,12 @@ import * as apiDefaults from './apigateway-defaults'; import { DefaultLogGroupProps } from './cloudwatch-log-group-defaults'; import { overrideProps } from './utils'; -/** - * Creates and configures an api.LambdaRestApi. - * @param scope - the construct to which the LambdaRestApi should be attached to. - * @param defaultApiGatewayProps - the default properties for the LambdaRestApi. - * @param apiGatewayProps - (optional) user-specified properties to override the default properties. - */ -function configureLambdaRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.LambdaRestApiProps, - apiGatewayProps?: api.LambdaRestApiProps): api.RestApi { - // Define the API object - let _api: api.RestApi; - if (apiGatewayProps) { - // If property overrides have been provided, incorporate them and deploy - const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); - _api = new api.LambdaRestApi(scope, 'RestApi', _apiGatewayProps); - } else { - // If no property overrides, deploy using the default configuration - _api = new api.LambdaRestApi(scope, 'RestApi', defaultApiGatewayProps); - } - // Configure API access logging - configureApiAccessLogging(scope, _api); - - // Configure Usage Plan - _api.addUsagePlan('UsagePlan', { - apiStages: [{ - api: _api, - stage: _api.deploymentStage - }] - }); - - // Return the API object - return _api; -} - /** * Create and configures access logging for API Gateway resources. * @param scope - the construct to which the access logging capabilities should be attached to. * @param _api - an existing api.RestApi or api.LambdaRestApi. */ -function configureApiAccessLogging(scope: cdk.Construct, _api: api.RestApi): void { - // Configure log group for API Gateway AccessLogging - const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); - // Configure the API stage - const stage: api.CfnStage = _api.deploymentStage.node.findChild('Resource') as api.CfnStage; - stage.accessLogSetting = { - destinationArn: logGroup.logGroupArn, - format: "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" - }; - // Configure the API deployment - const deployment: api.CfnDeployment = _api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; - deployment.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W45', - reason: `ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource` - }] - } - }; +function configureCloudwatchRoleForApi(scope: cdk.Construct, _api: api.RestApi): void { // Setup the IAM Role for API Gateway CloudWatch access const restApiCloudwatchRole = new iam.Role(scope, 'LambdaRestApiCloudWatchRole', { assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), @@ -93,9 +42,8 @@ function configureApiAccessLogging(scope: cdk.Construct, _api: api.RestApi): voi 'logs:GetLogEvents', 'logs:FilterLogEvents' ], - resources: [`arn:aws:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] - }) - ] + resources: [`arn:aws:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] + })] }) } }); @@ -105,6 +53,50 @@ function configureApiAccessLogging(scope: cdk.Construct, _api: api.RestApi): voi cloudWatchRoleArn: restApiCloudwatchRole.roleArn }); cfnAccount.addDependsOn(CfnApi); + + // Suppress Cfn Nag warning for APIG + const deployment: api.CfnDeployment = _api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; + deployment.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W45', + reason: `ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource` + }] + } + }; +} + +/** + * Creates and configures an api.LambdaRestApi. + * @param scope - the construct to which the LambdaRestApi should be attached to. + * @param defaultApiGatewayProps - the default properties for the LambdaRestApi. + * @param apiGatewayProps - (optional) user-specified properties to override the default properties. + */ +function configureLambdaRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.LambdaRestApiProps, + apiGatewayProps?: api.LambdaRestApiProps): api.RestApi { + // Define the API object + let _api: api.RestApi; + if (apiGatewayProps) { + // If property overrides have been provided, incorporate them and deploy + const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); + _api = new api.LambdaRestApi(scope, 'LambdaRestApi', _apiGatewayProps); + } else { + // If no property overrides, deploy using the default configuration + _api = new api.LambdaRestApi(scope, 'LambdaRestApi', defaultApiGatewayProps); + } + // Configure API access logging + configureCloudwatchRoleForApi(scope, _api); + + // Configure Usage Plan + _api.addUsagePlan('UsagePlan', { + apiStages: [{ + api: _api, + stage: _api.deploymentStage + }] + }); + + // Return the API object + return _api; } /** @@ -126,7 +118,7 @@ function configureRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.Rest _api = new api.RestApi(scope, 'RestApi', defaultApiGatewayProps); } // Configure API access logging - configureApiAccessLogging(scope, _api); + configureCloudwatchRoleForApi(scope, _api); // Configure Usage Plan _api.addUsagePlan('UsagePlan', { @@ -148,7 +140,11 @@ function configureRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.Rest */ export function GlobalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: lambda.Function, apiGatewayProps?: api.LambdaRestApiProps): api.RestApi { - const defaultProps = apiDefaults.DefaultGlobalLambdaRestApiProps(_existingLambdaObj); + + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + + const defaultProps = apiDefaults.DefaultGlobalLambdaRestApiProps(_existingLambdaObj, logGroup); return configureLambdaRestApi(scope, defaultProps, apiGatewayProps); } @@ -160,7 +156,10 @@ export function GlobalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: la */ export function RegionalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: lambda.Function, apiGatewayProps?: api.LambdaRestApiProps): api.RestApi { - const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(_existingLambdaObj); + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + + const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(_existingLambdaObj, logGroup); return configureLambdaRestApi(scope, defaultProps, apiGatewayProps); } @@ -170,6 +169,9 @@ export function RegionalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function GlobalRestApi(scope: cdk.Construct, apiGatewayProps?: api.RestApiProps): api.RestApi { - const defaultProps = apiDefaults.DefaultGlobalApiProps(); + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + + const defaultProps = apiDefaults.DefaultGlobalRestApiProps(logGroup); return configureRestApi(scope, defaultProps, apiGatewayProps); } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-defaults.ts b/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-defaults.ts index d23a0e990..be9383060 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-defaults.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-defaults.ts @@ -14,14 +14,18 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import * as api from '@aws-cdk/aws-apigateway'; +import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; export function DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint: api.RestApi, - loggingBucket?: s3.Bucket): cloudfront.CloudFrontWebDistributionProps { + loggingBucket: s3.Bucket, + setHttpSecurityHeaders: boolean, + edgeLambda?: lambda.Version): cloudfront.CloudFrontWebDistributionProps { + const apiEndPointUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split("://", apiEndPoint.url)); const apiEndPointDomainName = cdk.Fn.select(0, cdk.Fn.split("/", apiEndPointUrlWithoutProtocol)); - if (loggingBucket) { + if (setHttpSecurityHeaders) { return { originConfigs: [{ customOriginSource: { @@ -29,6 +33,12 @@ export function DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint: }, behaviors: [{ isDefaultBehavior: true, + lambdaFunctionAssociations: [ + { + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + lambdaFunction: edgeLambda + } + ] }] }], loggingConfig: { @@ -44,27 +54,55 @@ export function DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint: behaviors: [{ isDefaultBehavior: true, }] - }] + }], + loggingConfig: { + bucket: loggingBucket + } } as cloudfront.CloudFrontWebDistributionProps; } } export function DefaultCloudFrontWebDistributionForS3Props(sourceBucket: s3.Bucket, loggingBucket: s3.Bucket, - _originAccessIdentity: cloudfront.IOriginAccessIdentity): + _originAccessIdentity: cloudfront.IOriginAccessIdentity, + setHttpSecurityHeaders: boolean, + edgeLambda?: lambda.Version): cloudfront.CloudFrontWebDistributionProps { - const cfDistributionProps: cloudfront.CloudFrontWebDistributionProps = { - originConfigs: [ { - s3OriginSource: { - s3BucketSource: sourceBucket, - originAccessIdentity: _originAccessIdentity - }, - behaviors: [ { + + if (setHttpSecurityHeaders) { + return { + originConfigs: [{ + s3OriginSource: { + s3BucketSource: sourceBucket, + originAccessIdentity: _originAccessIdentity + }, + behaviors: [{ isDefaultBehavior: true, - } ] - } ], - loggingConfig: { - bucket: loggingBucket - } - } as cloudfront.CloudFrontWebDistributionProps; - return cfDistributionProps; + lambdaFunctionAssociations: [ + { + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + lambdaFunction: edgeLambda + } + ] + }] + }], + loggingConfig: { + bucket: loggingBucket + } + } as cloudfront.CloudFrontWebDistributionProps; + } else { + return { + originConfigs: [ { + s3OriginSource: { + s3BucketSource: sourceBucket, + originAccessIdentity: _originAccessIdentity + }, + behaviors: [ { + isDefaultBehavior: true, + } ] + } ], + loggingConfig: { + bucket: loggingBucket + } + } as cloudfront.CloudFrontWebDistributionProps; + } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-helper.ts index b4c277e9e..5314f3cca 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/cloudfront-distribution-helper.ts @@ -16,53 +16,27 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as iam from '@aws-cdk/aws-iam'; import * as api from '@aws-cdk/aws-apigateway'; +import * as lambda from '@aws-cdk/aws-lambda'; import { DefaultS3Props } from './s3-bucket-defaults'; import { DefaultCloudFrontWebDistributionForS3Props, DefaultCloudFrontWebDistributionForApiGatewayProps } from './cloudfront-distribution-defaults'; import { overrideProps } from './utils'; +import { deployLambdaFunction } from './lambda-helper'; -export function CloudFrontDistributionForApiGateway(scope: cdk.Construct, apiEndPoint: api.RestApi, cloudFrontDistributionProps?: - cloudfront.CloudFrontWebDistributionProps | any): cloudfront.CloudFrontWebDistribution { - - let defaultprops; - - if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingBucket) { - defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint); - } else { - // Create the Logging Bucket - const loggingBucket: s3.Bucket = new s3.Bucket(scope, 'CloudfrontLoggingBucket', DefaultS3Props()); - - // Extract the CfnBucket from the loggingBucket - const loggingBucketResource = loggingBucket.node.findChild('Resource') as s3.CfnBucket; - - // Override accessControl configuration and add metadata for the logging bucket - loggingBucketResource.addPropertyOverride('AccessControl', 'LogDeliveryWrite'); - loggingBucketResource.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W35', - reason: `This S3 bucket is used as the access logging bucket for CloudFront Distribution` - }, { - id: 'W51', - reason: `This S3 bucket is used as the access logging bucket for CloudFront Distribution` - }] - } - }; - - defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, loggingBucket); - } - - // Create the Cloudfront Distribution - let cfprops = defaultprops; - if (cloudFrontDistributionProps) { - cfprops = overrideProps(defaultprops, cloudFrontDistributionProps); - } - const cfDistribution: cloudfront.CloudFrontWebDistribution = new cloudfront.CloudFrontWebDistribution(scope, 'CloudFrontDistribution', cfprops); - +// Override Cfn_Nag rule: Cloudfront TLS-1.2 rule (https://github.com/stelligent/cfn_nag/issues/384) +function updateSecurityPolicy(cfDistribution: cloudfront.CloudFrontWebDistribution) { + const cfnCfDistribution = cfDistribution.node.defaultChild as cloudfront.CfnDistribution; + cfnCfDistribution.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W70', + reason: `Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion` + }] + } + }; return cfDistribution; } -export function CloudFrontDistributionForS3(scope: cdk.Construct, sourceBucket: s3.Bucket, cloudFrontDistributionProps?: - cloudfront.CloudFrontWebDistributionProps | any): cloudfront.CloudFrontWebDistribution { +function createCloudfrontLoggingBucket(scope: cdk.Construct): s3.Bucket { // Create the Logging Bucket const loggingBucket: s3.Bucket = new s3.Bucket(scope, 'CloudfrontLoggingBucket', DefaultS3Props()); @@ -83,6 +57,104 @@ export function CloudFrontDistributionForS3(scope: cdk.Construct, sourceBucket: } }; + return loggingBucket; +} + +// Lambda@Edge function to insert the HTTP Security Headers into the response coming from the origin servers +// and before it is sent to the client +function defaultLambdaEdgeFunction(scope: cdk.Construct): lambda.Function { + const edgeLambdaFunc: lambda.Function = deployLambdaFunction(scope, { + code: new lambda.InlineCode("exports.handler = (event, context, callback) => { \ + const response = event.Records[0].cf.response; \ + const headers = response.headers; \ + headers['x-xss-protection'] = [ \ + { \ + key: 'X-XSS-Protection', \ + value: '1; mode=block' \ + } \ + ]; \ + headers['x-frame-options'] = [ \ + { \ + key: 'X-Frame-Options', \ + value: 'DENY' \ + } \ + ]; \ + headers['x-content-type-options'] = [ \ + { \ + key: 'X-Content-Type-Options', \ + value: 'nosniff' \ + } \ + ]; \ + headers['strict-transport-security'] = [ \ + { \ + key: 'Strict-Transport-Security', \ + value: 'max-age=63072000; includeSubdomains; preload' \ + } \ + ]; \ + headers['referrer-policy'] = [ \ + { \ + key: 'Referrer-Policy', \ + value: 'same-origin' \ + } \ + ]; \ + headers['content-security-policy'] = [ \ + { \ + key: 'Content-Security-Policy', \ + value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" \ + } \ + ]; \ + callback(null, response); \ + };"), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, 'SetHttpSecurityHeaders'); + + // Remove any environment variables as it is not supported by the Lambda@Edge functions :( + const cfnEdgeLambdaFunction = edgeLambdaFunc.node.defaultChild as lambda.CfnFunction; + cfnEdgeLambdaFunction.addDeletionOverride('Properties.Environment'); + + return edgeLambdaFunc; +} + +export function CloudFrontDistributionForApiGateway(scope: cdk.Construct, + apiEndPoint: api.RestApi, + cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any, + httpSecurityHeaders?: boolean): cloudfront.CloudFrontWebDistribution { + + const _httpSecurityHeaders = httpSecurityHeaders ? httpSecurityHeaders : true; + let defaultprops: cloudfront.CloudFrontWebDistributionProps; + let edgeLambdaVersion; + + if (_httpSecurityHeaders) { + edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { + lambda: defaultLambdaEdgeFunction(scope) + }); + } + + if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { + defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, + cloudFrontDistributionProps.loggingConfig.bucket, _httpSecurityHeaders, + edgeLambdaVersion); + } else { + const loggingBucket = createCloudfrontLoggingBucket(scope); + defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, + loggingBucket, _httpSecurityHeaders, + edgeLambdaVersion); + } + + const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; + // Create the Cloudfront Distribution + const cfDistribution: cloudfront.CloudFrontWebDistribution = new cloudfront.CloudFrontWebDistribution(scope, 'CloudFrontDistribution', cfprops); + updateSecurityPolicy(cfDistribution); + + return cfDistribution; +} + +export function CloudFrontDistributionForS3(scope: cdk.Construct, + sourceBucket: s3.Bucket, + cloudFrontDistributionProps?: cloudfront.CloudFrontWebDistributionProps | any, + httpSecurityHeaders?: boolean): cloudfront.CloudFrontWebDistribution { + // Create CloudFront Origin Access Identity User const cfnOrigAccessId = new cloudfront.CfnCloudFrontOriginAccessIdentity(scope, 'CloudFrontOriginAccessIdentity', { cloudFrontOriginAccessIdentityConfig: { @@ -96,13 +168,31 @@ export function CloudFrontDistributionForS3(scope: cdk.Construct, sourceBucket: cfnOrigAccessId.ref ); - // Create the Cloudfront Distribution - const defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, loggingBucket, oaiImported); - let cfprops = defaultprops; - if (cloudFrontDistributionProps) { - cfprops = overrideProps(defaultprops, cloudFrontDistributionProps); + let defaultprops: cloudfront.CloudFrontWebDistributionProps; + let edgeLambdaVersion; + const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; + + if (_httpSecurityHeaders) { + edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { + lambda: defaultLambdaEdgeFunction(scope) + }); } + + if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { + defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, + cloudFrontDistributionProps.loggingConfig.bucket, oaiImported, _httpSecurityHeaders, + edgeLambdaVersion); + } else { + const loggingBucket = createCloudfrontLoggingBucket(scope); + defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, loggingBucket, + oaiImported, _httpSecurityHeaders, + edgeLambdaVersion); + } + + const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; + // Create the Cloudfront Distribution const cfDistribution: cloudfront.CloudFrontWebDistribution = new cloudfront.CloudFrontWebDistribution(scope, 'CloudFrontDistribution', cfprops); + updateSecurityPolicy(cfDistribution); // Add S3 Bucket Policy to allow s3:GetObject for CloudFront Origin Access Identity User sourceBucket.addToResourcePolicy(new iam.PolicyStatement({ @@ -117,8 +207,8 @@ export function CloudFrontDistributionForS3(scope: cdk.Construct, sourceBucket: sourceBucketPolicy.cfnOptions.metadata = { cfn_nag: { rules_to_suppress: [{ - id: 'F16', - reason: `Public website bucket policy requires a wildcard principal` + id: 'F16', + reason: `Public website bucket policy requires a wildcard principal` }] } }; diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/cognito-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/cognito-helper.ts index 37d0651f1..3422ade91 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/cognito-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/cognito-helper.ts @@ -41,6 +41,22 @@ export function buildUserPool(scope: cdk.Construct, userPoolProps?: cognito.User advancedSecurityMode: 'ENFORCED' }; + // Add Cfn Nag suppress for the cognito SMS role policy + const userPoolSmsRole = userPool.node.tryFindChild('smsRole') as iam.Role; + + if (userPoolSmsRole) { + const cfnuserPoolSmsRole = userPoolSmsRole.node.defaultChild as iam.CfnRole; + + cfnuserPoolSmsRole.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W11', + reason: `Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish` + }] + } + }; + } + return userPool; } diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/kinesis-streams-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/kinesis-streams-helper.ts index 0f91ae987..dd69f3446 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/kinesis-streams-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/kinesis-streams-helper.ts @@ -38,7 +38,7 @@ export function buildKinesisStream(scope: cdk.Construct, props?: BuildKinesisStr props = (props === undefined) ? {} : props; // Setup the stream properties let kinesisStreamProps; - if (props.hasOwnProperty('kinesisStreamProps')) { + if (props.kinesisStreamProps) { // If property overrides have been provided, incorporate them and deploy kinesisStreamProps = overrideProps(DefaultStreamProps, props.kinesisStreamProps); } else { diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/kms-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/kms-helper.ts index 40678d57c..f56be533e 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/kms-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/kms-helper.ts @@ -31,7 +31,7 @@ export function buildEncryptionKey(scope: cdk.Construct, props?: BuildEncryption props = (props === undefined) ? {} : props; // Setup the key properties let encryptionKeyProps; - if (props.hasOwnProperty('encryptionKeyProps')) { + if (props.encryptionKeyProps) { // If property overrides have been provided, incorporate them and deploy encryptionKeyProps = overrideProps(DefaultEncryptionProps, props.encryptionKeyProps); } else { diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/lambda-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/lambda-helper.ts index c7e48e9ab..5400792fb 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/lambda-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/lambda-helper.ts @@ -60,9 +60,15 @@ export function buildLambdaFunction(scope: cdk.Construct, props: BuildLambdaFunc } } -export function deployLambdaFunction(scope: cdk.Construct, lambdaFunctionProps: lambda.FunctionProps): lambda.Function { +export function deployLambdaFunction(scope: cdk.Construct, + lambdaFunctionProps: lambda.FunctionProps, + functionId?: string): lambda.Function { + + const _functionId = functionId ? functionId : 'LambdaFunction'; + const _functionRoleId = _functionId + 'ServiceRole'; + // Setup the IAM Role for Lambda Service - const lambdaServiceRole = new iam.Role(scope, 'LambdaFunctionServiceRole', { + const lambdaServiceRole = new iam.Role(scope, _functionRoleId, { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), inlinePolicies: { LambdaFunctionServiceRolePolicy: new iam.PolicyDocument({ @@ -86,7 +92,7 @@ export function deployLambdaFunction(scope: cdk.Construct, lambdaFunctionProps: _lambdaFunctionProps = overrideProps(DefaultLambdaFunctionPropsForNodeJS(lambdaServiceRole), lambdaFunctionProps); } - const lambdafunction = new lambda.Function(scope, 'LambdaFunction', _lambdaFunctionProps); + const lambdafunction = new lambda.Function(scope, _functionId, _lambdaFunctionProps); const cfnLambdafunction = lambdafunction.node.findChild('Resource') as lambda.CfnFunction; diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/override-warning-service.ts b/source/patterns/@aws-solutions-konstruk/core/lib/override-warning-service.ts new file mode 100644 index 000000000..973e89ecf --- /dev/null +++ b/source/patterns/@aws-solutions-konstruk/core/lib/override-warning-service.ts @@ -0,0 +1,86 @@ +/** + * Copyright 2019 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 * as deepdiff from 'deep-diff'; +import * as log from 'npmlog'; + +/** + * Emits a warning to the console when a prescriptive default value is overridden by the user. + * @param {objet} defaultProps the prescriptive defaults for the pattern. + * @param {object} userProps the properties provided by the user, to be compared against the defaultProps. + */ +export function flagOverriddenDefaults(defaultProps: object, userProps: object) { + // Compare the properties and return any overrides + const overrides = findOverrides(defaultProps, userProps); + // Emit a warning for each override + for (let i = 0; i < ((overrides !== undefined) ? overrides.length : 0); i++) { + const e = Object.assign(overrides[i]); + // Determine appropriate logging granularity + const valuesAreReadable = ( + checkReadability(e.lhs) && + checkReadability(e.rhs) + ); + // Format the path for readability + const path = formatOverridePath(e.path); + // Style the log output + log.prefixStyle.bold = true; + log.prefixStyle.fg = 'red'; + log.enableColor(); + // Output + const details = (valuesAreReadable) ? ` Default value: '${e.lhs}'. You provided: '${e.rhs}'.` : ''; + log.warn('AWS_KONSTRUK_WARNING: ', `An override has been provided for the property: ${path}.` + details); + } +} + +/** + * Performs a diff check of the userProps against the defaultProps to detect overridden properties. + * @param {object} defaultProps the prescriptive defaults for the pattern. + * @param {object} userProps the properties provided by the user, to be compared against the defaultProps. + * @return {Array} an array containing the overridden values. + */ +function findOverrides(defaultProps: object, userProps: object) { + const diff = deepdiff.diff(defaultProps, userProps); + // Filter the results + return (diff !== undefined) ? diff?.filter((e) => ( + e.kind === 'E' && // only return overrides + !e.path?.includes('node') && // stop traversing once the object graph hits the node + !e.path?.includes('bind') // stop traversing once the object graph hits internal functions + )) : []; +} + +/** + * Converts the path object from the deep-diff module to a user-readable, bracket notation format. + * @param {string | string[]} path either a string value or an array of strings. + * @return {string} the formatted override path. + */ +function formatOverridePath(path: string | string[]) { + return (path !== undefined && path.length > 1) ? path.toString() + .replace(/,/g, '][') + .replace(/\]{1}/, '') + .replace(/$/, ']') : path; +} + +/** + * Check the readability of an input value and, in the context of the override warning service, return true if it + * meets the established criteria. This function is used to determine whether more-detailed log output can be given. + * @param {any} value input to be evaluated against the given criteria. + * @return {boolean} true if the value meets the given criteria. + * @return {boolean} false if the value does not meet the given criteria. + */ +function checkReadability(value: any) { + return ( + typeof(value) === 'string' && // strings only + !value.includes('${Token[') && // no circular refs + value !== '' // no empty strings + ); +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/sqs-defaults.ts b/source/patterns/@aws-solutions-konstruk/core/lib/sqs-defaults.ts index 9df6b1f21..d092731d8 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/sqs-defaults.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/sqs-defaults.ts @@ -20,4 +20,7 @@ export function DefaultQueueProps(_encryptionMasterKey?: kms.Key) { encryptionMasterKey: _encryptionMasterKey }; return _DefaultQueueProps; -} \ No newline at end of file +} + +// Default value for the max receive count of a dead letter queue +export const defaultMaxReceiveCount = 15; \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/sqs-helper.ts b/source/patterns/@aws-solutions-konstruk/core/lib/sqs-helper.ts index b22d454e5..a2193e40e 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/sqs-helper.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/sqs-helper.ts @@ -71,13 +71,14 @@ export interface BuildDeadLetterQueueProps { * * @default - Default props are used */ - readonly maxReceiveCount: number + readonly maxReceiveCount?: number } export function buildDeadLetterQueue(props: BuildDeadLetterQueueProps): sqs.DeadLetterQueue { + const mrc = (props.maxReceiveCount) ? props.maxReceiveCount : defaults.defaultMaxReceiveCount; // Setup the queue interface and return const dlq: sqs.DeadLetterQueue = { - maxReceiveCount: props.maxReceiveCount, + maxReceiveCount: mrc, queue: props.deadLetterQueue }; return dlq; diff --git a/source/patterns/@aws-solutions-konstruk/core/lib/utils.ts b/source/patterns/@aws-solutions-konstruk/core/lib/utils.ts index 5dd07a3a7..424fce576 100644 --- a/source/patterns/@aws-solutions-konstruk/core/lib/utils.ts +++ b/source/patterns/@aws-solutions-konstruk/core/lib/utils.ts @@ -12,6 +12,7 @@ */ import * as deepmerge from 'deepmerge'; +import { flagOverriddenDefaults } from './override-warning-service'; function isObject(val: object) { return val != null && typeof val === 'object' @@ -58,17 +59,21 @@ function overwriteMerge(target: any[], source: any[]) { } export function overrideProps(DefaultProps: object, userProps: object, concatArray: boolean = false): any { - // Override the sensible defaults with user provided props - - if (concatArray) { - return deepmerge(DefaultProps, userProps, { - arrayMerge: combineMerge, - isMergeableObject: isPlainObject - }); - } else { - return deepmerge(DefaultProps, userProps, { - arrayMerge: overwriteMerge, - isMergeableObject: isPlainObject - }); - } + // Notify the user via console output if defaults are overridden + const overrideWarningsEnabled = (process.env.overrideWarningsEnabled !== 'false'); + if (overrideWarningsEnabled) { + flagOverriddenDefaults(DefaultProps, userProps); + } + // Override the sensible defaults with user provided props + if (concatArray) { + return deepmerge(DefaultProps, userProps, { + arrayMerge: combineMerge, + isMergeableObject: isPlainObject + }); + } else { + return deepmerge(DefaultProps, userProps, { + arrayMerge: overwriteMerge, + isMergeableObject: isPlainObject + }); + } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/package.json b/source/patterns/@aws-solutions-konstruk/core/package.json index bc9a3465e..76287da2a 100644 --- a/source/patterns/@aws-solutions-konstruk/core/package.json +++ b/source/patterns/@aws-solutions-konstruk/core/package.json @@ -1,9 +1,9 @@ { "name": "@aws-solutions-konstruk/core", - "version": "0.8.0", + "version": "0.8.1", "description": "Core CDK Construct for patterns library", "main": "index.js", - "types": "index.d.ts", + "types": "index.ts", "repository": { "type": "git", "url": "https://github.com/awslabs/aws-solutions-konstruk.git", @@ -52,30 +52,34 @@ } }, "dependencies": { - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kinesisanalytics": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-events": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0", - "deepmerge": "^4.0.0" + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kinesisanalytics": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-events": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0", + "@types/deep-diff": "^1.0.0", + "@types/npmlog": "^4.1.2", + "deep-diff": "^1.0.2", + "deepmerge": "^4.0.0", + "npmlog": "^4.1.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -85,28 +89,32 @@ ] }, "bundledDependencies": [ - "deepmerge" + "deepmerge", + "npmlog", + "@types/npmlog", + "deep-diff", + "@types/deep-diff" ], "peerDependencies": { - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-cdk/aws-iot": "~1.25.0", - "@aws-cdk/aws-kinesis": "~1.25.0", - "@aws-cdk/aws-kinesisanalytics": "~1.25.0", - "@aws-cdk/aws-kinesisfirehose": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-lambda-event-sources": "~1.25.0", - "@aws-cdk/aws-logs": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/aws-sns": "~1.25.0", - "@aws-cdk/aws-sqs": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-kms": "~1.25.0", - "@aws-cdk/aws-events": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-elasticsearch": "~1.25.0", - "@aws-cdk/aws-cloudwatch": "~1.25.0" + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-cdk/aws-iot": "~1.40.0", + "@aws-cdk/aws-kinesis": "~1.40.0", + "@aws-cdk/aws-kinesisanalytics": "~1.40.0", + "@aws-cdk/aws-kinesisfirehose": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-lambda-event-sources": "~1.40.0", + "@aws-cdk/aws-logs": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/aws-sns": "~1.40.0", + "@aws-cdk/aws-sqs": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-kms": "~1.40.0", + "@aws-cdk/aws-events": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-elasticsearch": "~1.40.0", + "@aws-cdk/aws-cloudwatch": "~1.40.0" } } diff --git a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/apigateway-helper.test.js.snap b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/apigateway-helper.test.js.snap index 08a773a2f..7a58809aa 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/apigateway-helper.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/apigateway-helper.test.js.snap @@ -116,7 +116,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiDeployment180EC50321995420db12611041100554516080b6": Object { + "RestApiDeployment180EC503ff9f4e58fcd809ac9d74444c77261a4c": Object { "DependsOn": Array [ "RestApiapigatewayresourcePOST2678115A", "RestApiapigatewayresource242D19A1", @@ -148,10 +148,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC50321995420db12611041100554516080b6", + "Ref": "RestApiDeployment180EC503ff9f4e58fcd809ac9d74444c77261a4c", }, "MethodSettings": Array [ Object { @@ -391,7 +391,7 @@ Object { }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiDeployment180EC50321995420db12611041100554516080b6": Object { + "RestApiDeployment180EC503633ccd280519f1c2d0918bcc8026be3c": Object { "DependsOn": Array [ "RestApiapigatewayresourcePOST2678115A", "RestApiapigatewayresource242D19A1", @@ -423,10 +423,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC50321995420db12611041100554516080b6", + "Ref": "RestApiDeployment180EC503633ccd280519f1c2d0918bcc8026be3c", }, "MethodSettings": Array [ Object { @@ -553,14 +553,14 @@ Object { exports[`snapshot test RegionalApiGateway default params 1`] = ` Object { "Outputs": Object { - "RestApiEndpoint0551178A": Object { + "LambdaRestApiEndpointCCECE4C1": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, ".execute-api.", Object { @@ -572,7 +572,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/", ], @@ -720,87 +720,18 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "RestApi0C43BF4B": Object { + "LambdaRestApi95870433": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "REGIONAL", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "LambdaRestApiANYA831AD87": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -833,17 +764,17 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "LambdaRestApi95870433", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionRestApiANY3A99B4EE": Object { + "LambdaRestApiANYApiPermissionLambdaRestApiANYD56C5914": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -871,11 +802,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/*/", ], @@ -884,7 +815,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestRestApiANY79BD91F2": Object { + "LambdaRestApiANYApiPermissionTestLambdaRestApiANY9B2403A7": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -912,7 +843,7 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/test-invoke-stage/*/", ], @@ -921,11 +852,80 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8": Object { + "LambdaRestApiAccount": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", + "LambdaRestApi95870433", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "LambdaRestApiCloudWatchRoleF339D4E6", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "LambdaRestApiCloudWatchRoleF339D4E6": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7": Object { + "DependsOn": Array [ + "LambdaRestApiproxyANY93D43CC0", + "LambdaRestApiproxy9F99E187", + "LambdaRestApiANYA831AD87", ], "Metadata": Object { "cfn_nag": Object { @@ -940,12 +940,12 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "LambdaRestApiDeploymentStageprodB1F3862A": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { @@ -954,10 +954,10 @@ Object { "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503c4d635ab14db0b242903e058a000f3f8", + "Ref": "LambdaRestApiDeploymentBA640578812946cff1910fe2b8b339ee3a8d51c7", }, "MethodSettings": Array [ Object { @@ -968,21 +968,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiUsagePlan6E1C537A": Object { + "LambdaRestApiUsagePlanB4DF55D0": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "Throttle": Object {}, }, @@ -990,7 +990,22 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "LambdaRestApiproxy9F99E187": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "LambdaRestApi95870433", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "LambdaRestApi95870433", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "LambdaRestApiproxyANY93D43CC0": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -1022,15 +1037,15 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "LambdaRestApiproxy9F99E187", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionRestApiANYproxy9C9912F9": Object { + "LambdaRestApiproxyANYApiPermissionLambdaRestApiANYproxy208F31EB": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -1058,11 +1073,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "LambdaRestApiDeploymentStageprodB1F3862A", }, "/*/{proxy+}", ], @@ -1071,7 +1086,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestRestApiANYproxyCB7BC56D": Object { + "LambdaRestApiproxyANYApiPermissionTestLambdaRestApiANYproxyDBA3E731": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { @@ -1099,7 +1114,7 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "LambdaRestApi95870433", }, "/test-invoke-stage/*/{proxy+}", ], @@ -1108,21 +1123,6 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-api-gateway-helper.test.js.snap b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-api-gateway-helper.test.js.snap index 4dea3d1d2..e2e39f30f 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-api-gateway-helper.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-api-gateway-helper.test.js.snap @@ -46,6 +46,16 @@ Object { }, "Resources": Object { "CloudFrontDistributionCFDistribution599ADCC4": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -64,6 +74,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "SetHttpSecurityHeadersVersion660E2F72", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -444,7 +462,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "RestApiDeployment180EC503d2c6df3c8dc8b7193b98c1a0bff4e677": Object { + "RestApiDeployment180EC5037625dd9448e05124ef5f1cc2b6c3180a": Object { "DependsOn": Array [ "RestApiproxyANY1786B242", "RestApiproxyC95856DD", @@ -461,7 +479,7 @@ Object { "RestApiDeploymentStageprod3855DE66": Object { "Properties": Object { "DeploymentId": Object { - "Ref": "RestApiDeployment180EC503d2c6df3c8dc8b7193b98c1a0bff4e677", + "Ref": "RestApiDeployment180EC5037625dd9448e05124ef5f1cc2b6c3180a", }, "RestApiId": Object { "Ref": "RestApi0C43BF4B", @@ -603,6 +621,101 @@ Object { }, "Type": "AWS::ApiGateway::Resource", }, + "SetHttpSecurityHeadersEE936115": Object { + "DependsOn": Array [ + "SetHttpSecurityHeadersServiceRoleAF063E32", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "SetHttpSecurityHeadersServiceRoleAF063E32", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "SetHttpSecurityHeadersServiceRoleAF063E32": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "SetHttpSecurityHeadersVersion660E2F72": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "SetHttpSecurityHeadersEE936115", + }, + }, + "Type": "AWS::Lambda::Version", + }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-s3-helper.test.js.snap b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-s3-helper.test.js.snap index 56e065544..1cd4e4a36 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-s3-helper.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/cloudfront-distribution-s3-helper.test.js.snap @@ -4,6 +4,16 @@ exports[`cloudfront distribution with default params 1`] = ` Object { "Resources": Object { "CloudFrontDistributionCFDistribution599ADCC4": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -22,6 +32,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "SetHttpSecurityHeadersVersion660E2F72", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -284,6 +302,101 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, + "SetHttpSecurityHeadersEE936115": Object { + "DependsOn": Array [ + "SetHttpSecurityHeadersServiceRoleAF063E32", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "SetHttpSecurityHeadersServiceRoleAF063E32", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "SetHttpSecurityHeadersServiceRoleAF063E32": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "SetHttpSecurityHeadersVersion660E2F72": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "SetHttpSecurityHeadersEE936115", + }, + }, + "Type": "AWS::Lambda::Version", + }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/congnito-helper.test.js.snap b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/congnito-helper.test.js.snap index 373201104..197bb90a9 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/congnito-helper.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/congnito-helper.test.js.snap @@ -5,13 +5,80 @@ Object { "Resources": Object { "CognitoUserPool53E37E69": Object { "Properties": Object { - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "CognitoUserPool", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "CognitoUserPoolsmsRoleD08A84E9", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, + "CognitoUserPoolsmsRoleD08A84E9": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], + }, + }, + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "CognitoUserPool", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, }, } `; @@ -21,10 +88,30 @@ Object { "Resources": Object { "CognitoUserPool53E37E69": Object { "Properties": Object { - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "CognitoUserPool", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "CognitoUserPoolsmsRoleD08A84E9", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, @@ -36,6 +123,53 @@ Object { }, "Type": "AWS::Cognito::UserPoolClient", }, + "CognitoUserPoolsmsRoleD08A84E9": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], + }, + }, + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "CognitoUserPool", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, }, } `; diff --git a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/elasticsearch-helper.test.js.snap b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/elasticsearch-helper.test.js.snap index 958551ade..71d02185f 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/elasticsearch-helper.test.js.snap +++ b/source/patterns/@aws-solutions-konstruk/core/test/__snapshots__/elasticsearch-helper.test.js.snap @@ -190,10 +190,30 @@ Object { }, "CognitoUserPool53E37E69": Object { "Properties": Object { - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "CognitoUserPool", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "CognitoUserPoolsmsRoleD08A84E9", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, @@ -206,6 +226,53 @@ Object { }, "Type": "AWS::Cognito::UserPoolClient", }, + "CognitoUserPoolsmsRoleD08A84E9": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", + }, + ], + }, + }, + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "CognitoUserPool", + }, + }, + "Effect": "Allow", + "Principal": Object { + "Service": "cognito-idp.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "sns-publish", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, "ElasticsearchDomain": Object { "Metadata": Object { "cfn_nag": Object { diff --git a/source/patterns/@aws-solutions-konstruk/core/test/apigateway-helper.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/apigateway-helper.test.ts index a0ac15c63..cdd4922b3 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/apigateway-helper.test.ts +++ b/source/patterns/@aws-solutions-konstruk/core/test/apigateway-helper.test.ts @@ -30,6 +30,62 @@ function deployRegionalApiGateway(stack: Stack) { return defaults.RegionalLambdaRestApi(stack, fn); } +function setupRestApi(stack: Stack, apiProps?: any): void { + const restApi = defaults.GlobalRestApi(stack, apiProps); + // Setup the API Gateway resource + const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + // Setup the API Gateway Integration + const apiGatewayIntegration = new api.AwsIntegration({ + service: "sqs", + integrationHttpMethod: "POST", + options: { + passthroughBehavior: api.PassthroughBehavior.NEVER, + requestParameters: { + "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" + }, + requestTemplates: { + "application/x-www-form-urlencoded": "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")&MessageAttribute.1.Name=queryParam1&MessageAttribute.1.Value.StringValue=$input.params(\"query_param_1\")&MessageAttribute.1.Value.DataType=String" + }, + integrationResponses: [ + { + statusCode: "200", + responseTemplates: { + "text/html": "Success" + } + }, + { + statusCode: "500", + responseTemplates: { + "text/html": "Error" + }, + selectionPattern: "500" + } + ] + }, + path: '12345678' + "/" + 'thisqueuequeueName' + }); + // Setup the API Gateway method(s) + apiGatewayResource.addMethod('POST', apiGatewayIntegration, { + requestParameters: { + "method.request.querystring.query_param_1": true + }, + methodResponses: [ + { + statusCode: "200", + responseParameters: { + "method.response.header.Content-Type": true + } + }, + { + statusCode: "500", + responseParameters: { + "method.response.header.Content-Type": true + }, + } + ] + }); +} + test('snapshot test RegionalApiGateway default params', () => { const stack = new Stack(); deployRegionalApiGateway(stack); @@ -62,7 +118,7 @@ test('Test override for RegionalApiGateway', () => { "REGIONAL" ] }, - Name: "RestApi" + Name: "LambdaRestApi" } }, ResourcePart.CompleteDefinition); }); @@ -160,58 +216,24 @@ test('Test default RestApi deployment w/ ApiGatewayProps', () => { }); }); -function setupRestApi(stack: Stack, apiProps?: any): void { - const restApi = defaults.GlobalRestApi(stack, apiProps); - // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); - // Setup the API Gateway Integration - const apiGatewayIntegration = new api.AwsIntegration({ - service: "sqs", - integrationHttpMethod: "POST", - options: { - passthroughBehavior: api.PassthroughBehavior.NEVER, - requestParameters: { - "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" - }, - requestTemplates: { - "application/x-www-form-urlencoded": "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")&MessageAttribute.1.Name=queryParam1&MessageAttribute.1.Value.StringValue=$input.params(\"query_param_1\")&MessageAttribute.1.Value.DataType=String" - }, - integrationResponses: [ - { - statusCode: "200", - responseTemplates: { - "text/html": "Success" - } - }, - { - statusCode: "500", - responseTemplates: { - "text/html": "Error" - }, - selectionPattern: "500" - } +test('Test default RestApi deployment for Cloudwatch loggroup', () => { + const stack = new Stack(); + deployRegionalApiGateway(stack); + + expect(stack).toHaveResource('AWS::Logs::LogGroup', { + UpdateReplacePolicy: "Retain", + DeletionPolicy: "Retain" + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResource('AWS::ApiGateway::Stage', { + AccessLogSetting: { + DestinationArn: { + "Fn::GetAtt": [ + "ApiAccessLogGroupCEA70788", + "Arn" ] - }, - path: '12345678' + "/" + 'thisqueuequeueName' - }); - // Setup the API Gateway method(s) - apiGatewayResource.addMethod('POST', apiGatewayIntegration, { - requestParameters: { - "method.request.querystring.query_param_1": true }, - methodResponses: [ - { - statusCode: "200", - responseParameters: { - "method.response.header.Content-Type": true - } - }, - { - statusCode: "500", - responseParameters: { - "method.response.header.Content-Type": true - }, - } - ] + Format: "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}", + }, }); -} \ No newline at end of file +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/test/cloudfront-distribution-s3-helper.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/cloudfront-distribution-s3-helper.test.ts index 8f08f8dee..6a1f54049 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/cloudfront-distribution-s3-helper.test.ts +++ b/source/patterns/@aws-solutions-konstruk/core/test/cloudfront-distribution-s3-helper.test.ts @@ -17,6 +17,7 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; import { CloudFrontDistributionForS3 } from '../lib/cloudfront-distribution-helper'; import { buildS3Bucket } from '../lib/s3-bucket-helper'; import '@aws-cdk/assert/jest'; +import { Bucket } from '@aws-cdk/aws-s3'; test('cloudfront distribution with default params', () => { const stack = new Stack(); @@ -160,6 +161,263 @@ test('test cloudfront check bucket policy', () => { }); }); +test('test cloudfront with no security headers ', () => { + const stack = new Stack(); + const sourceBucket = buildS3Bucket(stack, { + deployBucket: true + }); + + CloudFrontDistributionForS3(stack, sourceBucket, {}, false); + + expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { + 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, + Logging: { + Bucket: { + "Fn::GetAtt": [ + "CloudfrontLoggingBucket3C3EFAA7", + "RegionalDomainName" + ] + }, + IncludeCookies: false + }, + Origins: [ + { + DomainName: { + "Fn::GetAtt": [ + "S3Bucket07682993", + "RegionalDomainName" + ] + }, + Id: "origin1", + S3OriginConfig: { + OriginAccessIdentity: { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + Ref: "CloudFrontOriginAccessIdentity" + } + ] + ] + } + } + } + ], + PriceClass: "PriceClass_100", + ViewerCertificate: { + CloudFrontDefaultCertificate: true + } + } + }); +}); + +test('test cloudfront override cloudfront custom domain names ', () => { + const stack = new Stack(); + const sourceBucket = buildS3Bucket(stack, { + deployBucket: true + }); + + const myprops = { + aliasConfiguration: { + acmCertRef: '/acm/mycertificate', + names: ['mydomains'] + } + }; + + CloudFrontDistributionForS3(stack, sourceBucket, myprops); + + expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { + DistributionConfig: { + Aliases: [ + "mydomains" + ], + DefaultCacheBehavior: { + AllowedMethods: [ + "GET", + "HEAD" + ], + CachedMethods: [ + "GET", + "HEAD" + ], + Compress: true, + ForwardedValues: { + Cookies: { + Forward: "none" + }, + QueryString: false + }, + LambdaFunctionAssociations: [ + { + EventType: "origin-response", + LambdaFunctionARN: { + Ref: "SetHttpSecurityHeadersVersion660E2F72" + } + } + ], + TargetOriginId: "origin1", + ViewerProtocolPolicy: "redirect-to-https" + }, + DefaultRootObject: "index.html", + Enabled: true, + HttpVersion: "http2", + IPV6Enabled: true, + Logging: { + Bucket: { + "Fn::GetAtt": [ + "CloudfrontLoggingBucket3C3EFAA7", + "RegionalDomainName" + ] + }, + IncludeCookies: false + }, + Origins: [ + { + DomainName: { + "Fn::GetAtt": [ + "S3Bucket07682993", + "RegionalDomainName" + ] + }, + Id: "origin1", + S3OriginConfig: { + OriginAccessIdentity: { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + Ref: "CloudFrontOriginAccessIdentity" + } + ] + ] + } + } + } + ], + PriceClass: "PriceClass_100", + ViewerCertificate: { + AcmCertificateArn: "/acm/mycertificate", + SslSupportMethod: "sni-only" + } + } + }); +}); + +test('test cloudfront override cloudfront logging bucket ', () => { + const stack = new Stack(); + const sourceBucket = buildS3Bucket(stack, { + deployBucket: true + }); + const loggingBucket = new Bucket(stack, 'loggingbucket'); + + const myprops = { + loggingConfig: { + bucket: loggingBucket, + includeCookies: true + } + }; + + CloudFrontDistributionForS3(stack, sourceBucket, myprops); + + expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { + DistributionConfig: { + DefaultCacheBehavior: { + AllowedMethods: [ + "GET", + "HEAD" + ], + CachedMethods: [ + "GET", + "HEAD" + ], + Compress: true, + ForwardedValues: { + Cookies: { + Forward: "none" + }, + QueryString: false + }, + LambdaFunctionAssociations: [ + { + EventType: "origin-response", + LambdaFunctionARN: { + Ref: "SetHttpSecurityHeadersVersion660E2F72" + } + } + ], + TargetOriginId: "origin1", + ViewerProtocolPolicy: "redirect-to-https" + }, + DefaultRootObject: "index.html", + Enabled: true, + HttpVersion: "http2", + IPV6Enabled: true, + Logging: { + Bucket: { + "Fn::GetAtt": [ + "loggingbucket6D73BD53", + "RegionalDomainName" + ] + }, + IncludeCookies : true + }, + Origins: [ + { + DomainName: { + "Fn::GetAtt": [ + "S3Bucket07682993", + "RegionalDomainName" + ] + }, + Id: "origin1", + S3OriginConfig: { + OriginAccessIdentity: { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + Ref: "CloudFrontOriginAccessIdentity" + } + ] + ] + } + } + } + ], + PriceClass: "PriceClass_100", + ViewerCertificate: { + CloudFrontDefaultCertificate: true + } + } + }); +}); + test('test cloudfront override properties', () => { const stack = new Stack(); const sourceBucket = buildS3Bucket(stack, { diff --git a/source/patterns/@aws-solutions-konstruk/core/test/congnito-helper.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/congnito-helper.test.ts index d6d9e45b9..6a3ed9052 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/congnito-helper.test.ts +++ b/source/patterns/@aws-solutions-konstruk/core/test/congnito-helper.test.ts @@ -37,13 +37,12 @@ test('Test override for buildUserPool', () => { const userpoolProps: cognito.UserPoolProps = { userPoolName: 'test', - signInType: cognito.SignInType.EMAIL_OR_PHONE + signInAliases: { username: false, email: true, phone: true } }; defaults.buildUserPool(stack, userpoolProps); expect(stack).toHaveResource('AWS::Cognito::UserPool', { - LambdaConfig: {}, UsernameAttributes: [ "email", "phone_number" diff --git a/source/patterns/@aws-solutions-konstruk/core/test/kinesis-streams-defaults.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/kinesis-streams-defaults.test.ts index a3862a026..a0ea6a97c 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/kinesis-streams-defaults.test.ts +++ b/source/patterns/@aws-solutions-konstruk/core/test/kinesis-streams-defaults.test.ts @@ -12,7 +12,7 @@ */ import { SynthUtils } from '@aws-cdk/assert'; -import { Stack } from '@aws-cdk/core'; +import { Stack, Duration } from '@aws-cdk/core'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as defaults from '../index'; import { overrideProps } from '../lib/utils'; @@ -30,7 +30,7 @@ test('test kinesisstream override RetentionPeriodHours', () => { const defaultProps = defaults.DefaultStreamProps; const inProps: kinesis.StreamProps = { - retentionPeriodHours: 48 + retentionPeriod: Duration.hours(48) }; const outProps = overrideProps(defaultProps, inProps); diff --git a/source/patterns/@aws-solutions-konstruk/core/test/lambda-event-source.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/lambda-event-source.test.ts index 18efbdacf..11adf1286 100644 --- a/source/patterns/@aws-solutions-konstruk/core/test/lambda-event-source.test.ts +++ b/source/patterns/@aws-solutions-konstruk/core/test/lambda-event-source.test.ts @@ -14,6 +14,7 @@ import * as defaults from '../index'; import { DynamoEventSourceProps } from '@aws-cdk/aws-lambda-event-sources'; import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; import '@aws-cdk/assert/jest'; test('test DynamoEventSourceProps', () => { @@ -36,4 +37,31 @@ test('test DynamoEventSourceProps override', () => { batchSize: 1, startingPosition: "LATEST" }); +}); + +test('test KinesisEventSourceProps', () => { + const streamArn = 'xyz'; + const props = defaults.DefaultKinesisEventSourceProps(streamArn); + expect(props).toEqual({ + eventSourceArn: "xyz" + }); +}); + +test('test S3EventSourceProps w/ default props', () => { + const props = defaults.S3EventSourceProps(); + expect(props).toEqual({ + events: ["s3:ObjectCreated:*"] + }); +}); + +test('test S3EventSourceProps w/ user props', () => { + const s3EventSourceProps = { + events: [ + s3.EventType.OBJECT_CREATED_POST + ] + }; + const props = defaults.S3EventSourceProps(s3EventSourceProps); + expect(props).toEqual({ + events: ["s3:ObjectCreated:Post"] + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-konstruk/core/test/override-warning-service.test.ts b/source/patterns/@aws-solutions-konstruk/core/test/override-warning-service.test.ts new file mode 100644 index 000000000..0927998f1 --- /dev/null +++ b/source/patterns/@aws-solutions-konstruk/core/test/override-warning-service.test.ts @@ -0,0 +1,206 @@ +/** + * Copyright 2019 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 '@aws-cdk/assert/jest'; +import * as log from 'npmlog'; +import * as process from 'process'; +import { flagOverriddenDefaults } from '../lib/override-warning-service'; +import { overrideProps } from '../'; + +// Mock setup +beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + delete process.env.overrideWarningsEnabled; +}); + +// -------------------------------------------------------------- +// Test override detection: positive, not-nested +// -------------------------------------------------------------- +test('Test override detection: positive, not-nested', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyA: 'new-valueA', + keyD: 'valueD' + }; + // Act + const warn = jest.spyOn(log, 'warn'); + flagOverriddenDefaults(a, b); + // Assert + expect(warn).toBeCalledTimes(1); +}); + +// -------------------------------------------------------------- +// Test override detection: negative, not-nested +// -------------------------------------------------------------- +test('Test override detection: negative, not-nested', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyD: 'valueD' + }; + // Act + const warn = jest.spyOn(log, 'warn'); + flagOverriddenDefaults(a, b); + // Assert + expect(warn).toBeCalledTimes(0); +}); + +// -------------------------------------------------------------- +// Test override detection: positive, nested +// -------------------------------------------------------------- +test('Test override detection: positive, nested', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC', + keyD: { + keyDA: 'valueDA', + keyDB: 'valueDB' + } + }; + const b = { + keyC: 'valueCAnew', + keyD: { + keyDA: 'valueDAnew' + } + }; + // Act + const warn = jest.spyOn(log, 'warn'); + flagOverriddenDefaults(a, b); + // Assert + expect(warn).toBeCalledTimes(2); +}); + +// -------------------------------------------------------------- +// Test override detection: negative, nested +// -------------------------------------------------------------- +test('Test override detection: negative, nested', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC', + keyD: { + keyDA: 'valueDA', + keyDB: 'valueDB' + } + }; + const b = { + keyD: { + keyDA: 'valueDA' + } + }; + // Act + const warn = jest.spyOn(log, 'warn'); + flagOverriddenDefaults(a, b); + // Assert + expect(warn).toBeCalledTimes(0); +}); + +// -------------------------------------------------------------- +// Test override warning on/off: default on +// -------------------------------------------------------------- +test('Test override warning on/off: default on', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyA: 'new-valueA', + keyD: 'valueD' + }; + // Act + const warn = jest.spyOn(log, 'warn'); + overrideProps(a, b); + // Assert + expect(warn).toBeCalledTimes(1); +}); + +// -------------------------------------------------------------- +// Test override warning on/off: explicit on +// -------------------------------------------------------------- +test('Test override warning on/off: explicit on', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyA: 'new-valueA', + keyD: 'valueD' + }; + process.env.overrideWarningsEnabled = 'true'; + // Act + const warn = jest.spyOn(log, 'warn'); + overrideProps(a, b); + // Assert + expect(warn).toBeCalledTimes(1); +}); + +// -------------------------------------------------------------- +// Test override warning on/off: explicit off +// -------------------------------------------------------------- +test('Test override warning on/off: explicit off', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyA: 'new-valueA', + keyD: 'valueD' + }; + // Act + const warn = jest.spyOn(log, 'warn'); + process.env.overrideWarningsEnabled = 'false'; + overrideProps(a, b); + // Assert + expect(warn).toBeCalledTimes(0); +}); + +// -------------------------------------------------------------- +// Test override warning on/off: undefined on +// -------------------------------------------------------------- +test('Test override warning on/off: undefined on', () => { + // Arrange + const a = { + keyA: 'valueA', + keyB: 'valueB', + keyC: 'valueC' + }; + const b = { + keyA: 'new-valueA', + keyD: 'valueD' + }; + // Act + const warn = jest.spyOn(log, 'warn'); + process.env.overrideWarningsEnabled = undefined; + overrideProps(a, b); + // Assert + expect(warn).toBeCalledTimes(1); +}); \ No newline at end of file diff --git a/source/tools/cdk-integ-tools/.gitignore b/source/tools/cdk-integ-tools/.gitignore new file mode 100644 index 000000000..0d6a251de --- /dev/null +++ b/source/tools/cdk-integ-tools/.gitignore @@ -0,0 +1,10 @@ +*.js +*.js.map +*.d.ts +dist + +.LAST_BUILD +*.snk +.nyc_output +coverage +nyc.config.js \ No newline at end of file diff --git a/source/tools/cdk-integ-tools/.npmignore b/source/tools/cdk-integ-tools/.npmignore new file mode 100644 index 000000000..89a519f1e --- /dev/null +++ b/source/tools/cdk-integ-tools/.npmignore @@ -0,0 +1,9 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +.LAST_BUILD +*.snk \ No newline at end of file diff --git a/LICENSE b/source/tools/cdk-integ-tools/LICENSE similarity index 89% rename from LICENSE rename to source/tools/cdk-integ-tools/LICENSE index 67db85882..b71ec1688 100644 --- a/LICENSE +++ b/source/tools/cdk-integ-tools/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -173,3 +172,30 @@ defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 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. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/source/tools/cdk-integ-tools/NOTICE b/source/tools/cdk-integ-tools/NOTICE new file mode 100644 index 000000000..bfccac9a7 --- /dev/null +++ b/source/tools/cdk-integ-tools/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/tools/cdk-integ-tools/README.md b/source/tools/cdk-integ-tools/README.md new file mode 100644 index 000000000..6e6ea1767 --- /dev/null +++ b/source/tools/cdk-integ-tools/README.md @@ -0,0 +1,61 @@ +# Integration Test Tools + +A testing tool for CDK constructs integration testing. + +Integration tests are modeled as CDK apps that are deployed by the developers. +If deployment succeeds, the synthesized template is saved in a local file and +"locked". During build, the test app is only synthesized and compared against +the checked-in file to protect against regressions. + +### Setup + +Create any number of files called `integ.*.ts` in your `test` directory. These +should be CDK apps containing a single stack. + +Add the following to your `package.json`': + +```json +{ + scripts: { + "test": ".... && cdk-integ-assert", + "integ": "cdk-integ" + }, + ... + devDependencies: { + "cdk-integ-tools": "*", + "aws-cdk": "*" + } +} +``` + +This installs two tools into your scripts: + + * When `npm test` is executed (during build), the `cdk-integ-assert` tool is + invoked. This tool will only synthesize the integration test stacks and + compare them to the .expected files. If the files differ (or do not exist), + the test will fail. + * When `npm run integ` is executed (manually by the developer), the `cdk-integ` + tool is invoked. This tool will actually attempt to deploy the integration + test stacks into the default environment. If it succeeds, the .expected file + will be updated to include the latest synthesized stack. + +## cdk-integ + +Usage: + + cdk-integ [TEST...] [--no-clean] [--verbose] + +Will deploy test stacks from `test/integ.*.js` and store the synthesized output +under `test/integ.*.expected.json`. + +* Optionally, you can specify a list of test `integ.*.js` files (they must be + under `test/`) to execute only a subset of the tests. +* Use `--no-clean` to skip the clean up of the stack. This is useful in case you + wish to manually examine the stack to ensure that the result is what you + expected. +* Use `--verbose` to print verbose output from `cdk` executions. + +## cdk-integ-assert + +No arguments - will synthesize all `test/integ.*.js` apps and compare them to +their `.expected.json` counterparts. diff --git a/source/tools/cdk-integ-tools/bin/cdk-integ b/source/tools/cdk-integ-tools/bin/cdk-integ new file mode 100755 index 000000000..b6d96f066 --- /dev/null +++ b/source/tools/cdk-integ-tools/bin/cdk-integ @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./cdk-integ.js'); diff --git a/source/tools/cdk-integ-tools/bin/cdk-integ-assert b/source/tools/cdk-integ-tools/bin/cdk-integ-assert new file mode 100755 index 000000000..9f90881c4 --- /dev/null +++ b/source/tools/cdk-integ-tools/bin/cdk-integ-assert @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./cdk-integ-assert.js'); diff --git a/source/tools/cdk-integ-tools/bin/cdk-integ-assert.ts b/source/tools/cdk-integ-tools/bin/cdk-integ-assert.ts new file mode 100644 index 000000000..0ca658490 --- /dev/null +++ b/source/tools/cdk-integ-tools/bin/cdk-integ-assert.ts @@ -0,0 +1,51 @@ +#!/usr/bin/env node +// Verify that all integration tests still match their expected output +import { diffTemplate, formatDifferences } from '@aws-cdk/cloudformation-diff'; +import { DEFAULT_SYNTH_OPTIONS, IntegrationTests } from '../lib/integ-helpers'; + +// tslint:disable:no-console + +async function main() { + const tests = await new IntegrationTests('test').fromCliArgs(); // always assert all tests + const failures: string[] = []; + + for (const test of tests) { + process.stdout.write(`Verifying ${test.name} against ${test.expectedFileName} ... `); + + if (!test.hasExpected()) { + throw new Error(`No such file: ${test.expectedFileName}. Run 'npm run integ'.`); + } + + const stackToDeploy = await test.determineTestStack(); + const expected = await test.readExpected(); + + const args = new Array(); + args.push('--no-path-metadata'); + args.push('--no-asset-metadata'); + args.push('--no-staging'); + const actual = await test.invoke(['--json', ...args, 'synth', ...stackToDeploy], { + json: true, + ...DEFAULT_SYNTH_OPTIONS + }); + + const diff = diffTemplate(expected, actual); + + if (!diff.isEmpty) { + failures.push(test.name); + process.stdout.write('CHANGED.\n'); + formatDifferences(process.stdout, diff); + } else { + process.stdout.write('OK.\n'); + } + } + + if (failures.length > 0) { + // tslint:disable-next-line:max-line-length + throw new Error(`Some stacks have changed. To verify that they still deploy successfully, run: 'npm run integ ${failures.join(' ')}'`); + } +} + +main().catch(e => { + console.error(e); + process.exit(1); +}); diff --git a/source/tools/cdk-integ-tools/bin/cdk-integ.ts b/source/tools/cdk-integ-tools/bin/cdk-integ.ts new file mode 100644 index 000000000..1112c1518 --- /dev/null +++ b/source/tools/cdk-integ-tools/bin/cdk-integ.ts @@ -0,0 +1,72 @@ +#!/usr/bin/env node +// Exercise all integ stacks and if they deploy, update the expected synth files +import * as yargs from 'yargs'; +import { DEFAULT_SYNTH_OPTIONS, IntegrationTests } from '../lib/integ-helpers'; + +// tslint:disable:no-console + +async function main() { + const argv = yargs + .usage('Usage: cdk-integ [TEST...]') + .option('list', { type: 'boolean', default: false, desc: 'List tests instead of running them' }) + .option('clean', { type: 'boolean', default: true, desc: 'Skips stack clean up after test is completed (use --no-clean to negate)' }) + .option('verbose', { type: 'boolean', default: false, alias: 'v', desc: 'Verbose logs' }) + .argv; + + const tests = await new IntegrationTests('test').fromCliArgs(argv._); + + if (argv.list) { + process.stdout.write(tests.map(t => t.name).join(' ') + '\n'); + return; + } + + for (const test of tests) { + console.error(`Trying to deploy ${test.name}`); + + const stackToDeploy = await test.determineTestStack(); + console.error(`Selected stack: ${stackToDeploy}`); + + const args = new Array(); + + // don't inject cloudformation metadata into template + args.push('--no-path-metadata'); + args.push('--no-asset-metadata'); + args.push('--no-staging'); + + // inject "--verbose" to the command line of "cdk" if we are in verbose mode + if (argv.verbose) { + args.push('--verbose'); + } + + try { + // tslint:disable-next-line:max-line-length + await test.invoke([ ...args, 'deploy', '--require-approval', 'never', ...stackToDeploy ], { + verbose: argv.verbose + // Note: no "context" and "env", so use default user settings! + }); + + console.error(`Success! Writing out reference synth.`); + + // If this all worked, write the new expectation file + const actual = await test.invoke([ ...args, '--json', 'synth', ...stackToDeploy ], { + json: true, + verbose: argv.verbose, + ...DEFAULT_SYNTH_OPTIONS + }); + + await test.writeExpected(actual); + } finally { + if (argv.clean) { + console.error(`Cleaning up.`); + await test.invoke(['destroy', '--force', ...stackToDeploy ]); + } else { + console.error('Skipping clean up (--no-clean).'); + } + } + } +} + +main().catch(e => { + console.error(e); + process.exit(1); +}); diff --git a/source/tools/cdk-integ-tools/lib/integ-helpers.ts b/source/tools/cdk-integ-tools/lib/integ-helpers.ts new file mode 100644 index 000000000..3b0871cc3 --- /dev/null +++ b/source/tools/cdk-integ-tools/lib/integ-helpers.ts @@ -0,0 +1,257 @@ +// Helper functions for integration tests +import { spawnSync } from 'child_process'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY } from '@aws-cdk/cx-api'; + +const CDK_INTEG_STACK_PRAGMA = '/// !cdk-integ'; + +export class IntegrationTests { + constructor(private readonly directory: string) { + } + + public async fromCliArgs(tests?: string[]): Promise { + let allTests = await this.discover(); + const all = allTests.map(x => x.name); + let foundAll = true; + + if (tests && tests.length > 0) { + // Pare down found tests to filter + allTests = allTests.filter(t => tests.includes(t.name)); + + const selectedNames = allTests.map(t => t.name); + for (const unmatched of tests.filter(t => !selectedNames.includes(t))) { + process.stderr.write(`No such integ test: ${unmatched}\n`); + foundAll = false; + } + } + + if (!foundAll) { + process.stderr.write(`Available tests: ${all.join(' ')}\n`); + return []; + } + + return allTests; + } + + public async discover(): Promise { + const files = await this.readTree(); + const integs = files.filter(fileName => path.basename(fileName).startsWith('integ.') && path.basename(fileName).endsWith('.js')); + return await this.request(integs); + } + + public async request(files: string[]): Promise { + return files.map(fileName => new IntegrationTest(this.directory, fileName)); + } + + private async readTree(): Promise { + const ret = new Array(); + + const rootDir = this.directory; + + async function recurse(dir: string) { + const files = await fs.readdir(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const statf = await fs.stat(fullPath); + if (statf.isFile()) { ret.push(fullPath.substr(rootDir.length + 1)); } + if (statf.isDirectory()) { await recurse(path.join(fullPath)); } + } + } + + await recurse(this.directory); + return ret; + } +} + +export class IntegrationTest { + public readonly expectedFileName: string; + private readonly expectedFilePath: string; + private readonly cdkContextPath: string; + private readonly sourceFilePath: string; + + constructor(private readonly directory: string, public readonly name: string) { + const baseName = this.name.endsWith('.js') ? this.name.substr(0, this.name.length - 3) : this.name; + this.expectedFileName = baseName + '.expected.json'; + this.expectedFilePath = path.join(this.directory, this.expectedFileName); + this.sourceFilePath = path.join(this.directory, this.name); + this.cdkContextPath = path.join(this.directory, 'cdk.context.json'); + } + + public async invoke(args: string[], options: { json?: boolean, context?: any, verbose?: boolean, env?: any } = { }): Promise { + // Write context to cdk.json, afterwards delete. We need to do this because there is no way + // to pass structured context data from the command-line, currently. + if (options.context) { + await this.writeCdkContext(options.context); + } else { + this.deleteCdkContext(); + } + + try { + const cdk = require.resolve('aws-cdk/bin/cdk'); + return exec([cdk, '-a', `node ${this.name}`, '--no-version-reporting'].concat(args), { + cwd: this.directory, + json: options.json, + verbose: options.verbose, + env: options.env + }); + } finally { + this.deleteCdkContext(); + } + } + + public hasExpected(): boolean { + return fs.existsSync(this.expectedFilePath); + } + + /** + * Returns the single test stack to use. + * + * If the test has a single stack, it will be chosen. Otherwise a pragma is expected within the + * test file the name of the stack: + * + * @example + * + * /// !cdk-integ + * + */ + public async determineTestStack(): Promise { + const pragma = (await this.readStackPragma()); + if (pragma.length > 0) { + return pragma; + } + + const stacks = (await this.invoke([ 'ls' ], { ...DEFAULT_SYNTH_OPTIONS })).split('\n'); + if (stacks.length !== 1) { + throw new Error(`"cdk-integ" can only operate on apps with a single stack.\n\n` + + ` If your app has multiple stacks, specify which stack to select by adding this to your test source:\n\n` + + ` ${CDK_INTEG_STACK_PRAGMA} STACK ...\n\n` + + ` Available stacks: ${stacks.join(' ')} (wildcards are also supported)\n`); + } + + return stacks; + } + + public async readExpected(): Promise { + return JSON.parse(await fs.readFile(this.expectedFilePath, { encoding: 'utf-8' })); + } + + public async writeExpected(actual: any) { + await fs.writeFile(this.expectedFilePath, JSON.stringify(actual, undefined, 2), { encoding: 'utf-8' }); + } + + private async writeCdkContext(config: any) { + await fs.writeFile(this.cdkContextPath, JSON.stringify(config, undefined, 2), { encoding: 'utf-8' }); + } + + private deleteCdkContext() { + if (fs.existsSync(this.cdkContextPath)) { + fs.unlinkSync(this.cdkContextPath); + } + + const cdkOutPath = path.join(this.directory, 'cdk.out'); + if (fs.existsSync(cdkOutPath)) { + fs.removeSync(cdkOutPath); + } + } + + /** + * Reads the test source file and looks for the "!cdk-integ" pragma. If it exists, returns it's + * contents. This allows integ tests to supply custom command line arguments to "cdk deploy" and "cdk synth". + */ + private async readStackPragma(): Promise { + const source = await fs.readFile(this.sourceFilePath, 'utf-8'); + const pragmaLine = source.split('\n').find(x => x.startsWith(CDK_INTEG_STACK_PRAGMA + ' ')); + if (!pragmaLine) { + return []; + } + + const args = pragmaLine.substring(CDK_INTEG_STACK_PRAGMA.length).trim().split(' '); + if (args.length === 0) { + throw new Error(`Invalid syntax for cdk-integ pragma. Usage: "${CDK_INTEG_STACK_PRAGMA} STACK ..."`); + } + return args; + } +} + +// Default context we run all integ tests with, so they don't depend on the +// account of the exercising user. +export const DEFAULT_SYNTH_OPTIONS = { + context: { + [AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY]: [ "test-region-1a", "test-region-1b", "test-region-1c" ], + "availability-zones:account=12345678:region=test-region": [ "test-region-1a", "test-region-1b", "test-region-1c" ], + "ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2:region=test-region": "ami-1234", + "ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:region=test-region": "ami-1234", + "ssm:account=12345678:parameterName=/aws/service/ecs/optimized-ami/amazon-linux/recommended:region=test-region": "{\"image_id\": \"ami-1234\"}", + // tslint:disable-next-line:max-line-length + "ami:account=12345678:filters.image-type.0=machine:filters.name.0=amzn-ami-vpc-nat-*:filters.state.0=available:owners.0=amazon:region=test-region": "ami-1234", + "vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true": { + vpcId: "vpc-60900905", + subnetGroups: [ + { + type: "Public", + name: "Public", + subnets: [ + { + subnetId: "subnet-e19455ca", + availabilityZone: "us-east-1a", + routeTableId: "rtb-e19455ca", + }, + { + subnetId: "subnet-e0c24797", + availabilityZone: "us-east-1b", + routeTableId: "rtb-e0c24797", + }, + { + subnetId: "subnet-ccd77395", + availabilityZone: "us-east-1c", + routeTableId: "rtb-ccd77395", + }, + ], + }, + ], + }, + }, + env: { + CDK_INTEG_ACCOUNT: "12345678", + CDK_INTEG_REGION: "test-region", + } +}; + +/** + * Our own execute function which doesn't use shells and strings. + */ +function exec(commandLine: string[], options: { cwd?: string, json?: boolean, verbose?: boolean, env?: any } = { }): any { + const proc = spawnSync(commandLine[0], commandLine.slice(1), { + stdio: [ 'ignore', 'pipe', options.verbose ? 'inherit' : 'pipe' ], // inherit STDERR in verbose mode + env: { + ...process.env, + CDK_INTEG_MODE: '1', + ...options.env, + }, + cwd: options.cwd + }); + + if (proc.error) { throw proc.error; } + if (proc.status !== 0) { + if (process.stderr) { // will be 'null' in verbose mode + process.stderr.write(proc.stderr); + } + throw new Error(`Command exited with ${proc.status ? `status ${proc.status}` : `signal ${proc.signal}`}`); + } + + const output = proc.stdout.toString('utf-8').trim(); + + try { + if (options.json) { + if (output.length === 0) { return {}; } + + return JSON.parse(output); + } + return output; + } catch (e) { + // tslint:disable-next-line:no-console + console.error("Not JSON: " + output); + throw new Error('Command output is not JSON'); + } +} diff --git a/source/tools/cdk-integ-tools/package.json b/source/tools/cdk-integ-tools/package.json new file mode 100644 index 000000000..9ec2c34e8 --- /dev/null +++ b/source/tools/cdk-integ-tools/package.json @@ -0,0 +1,48 @@ +{ + "name": "cdk-integ-tools", + "private": true, + "version": "1.24.0", + "description": "Package with integration test scripts for CDK packages", + "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "tools/cdk-integ-tools" + }, + "bin": { + "cdk-integ": "bin/cdk-integ", + "cdk-integ-assert": "bin/cdk-integ-assert" + }, + "scripts": { + "build": "tsc -b .", + "watch": "tsc -b -w", + "lint": "tslint --project ." + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/fs-extra": "^8.0.1", + "@types/yargs": "^15.0.3", + "tslint": "^5.20.1", + "typescript": "~3.7.4" + }, + "dependencies": { + "@aws-cdk/cloudformation-diff": "1.40.0", + "@aws-cdk/cx-api": "1.40.0", + "aws-cdk": "1.40.0", + "fs-extra": "^8.1.0", + "yargs": "^15.1.0" + }, + "keywords": [ + "aws", + "cdk" + ], + "homepage": "https://github.com/aws/aws-cdk", + "engines": { + "node": ">= 10.3.0" + } +} diff --git a/source/tools/cdk-integ-tools/tsconfig.json b/source/tools/cdk-integ-tools/tsconfig.json new file mode 100644 index 000000000..14499cd2a --- /dev/null +++ b/source/tools/cdk-integ-tools/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "lib": ["es2018"], + "strict": true, + "alwaysStrict": true, + "declaration": true, + "inlineSourceMap": true, + "inlineSources": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "resolveJsonModule": true, + "composite": true, + "incremental": true + }, + "include": ["**/*.ts"] +} diff --git a/source/use_cases/aws-s3-static-website/package.json b/source/use_cases/aws-s3-static-website/package.json index be6e3dd86..da341c72f 100644 --- a/source/use_cases/aws-s3-static-website/package.json +++ b/source/use_cases/aws-s3-static-website/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-s3-static-website", - "version": "0.8.0", + "version": "0.8.1", "description": "Use case pattern for deploying a S3 static website.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,19 +28,19 @@ "build+lint+test": "npm run build && npm run lint && npm test && npm run integ-assert" }, "dependencies": { - "@aws-solutions-konstruk/aws-cloudfront-s3": "~0.8.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/custom-resources": "~1.25.0", - "@aws-cdk/aws-cloudformation": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", + "@aws-solutions-konstruk/aws-cloudfront-s3": "~0.8.1", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/custom-resources": "~1.40.0", + "@aws-cdk/aws-cloudformation": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, diff --git a/source/use_cases/aws-s3-static-website/test/__snapshots__/s3-static-site-stack.test.js.snap b/source/use_cases/aws-s3-static-website/test/__snapshots__/s3-static-site-stack.test.js.snap index 2ab898e31..6c1adfa59 100644 --- a/source/use_cases/aws-s3-static-website/test/__snapshots__/s3-static-site-stack.test.js.snap +++ b/source/use_cases/aws-s3-static-website/test/__snapshots__/s3-static-site-stack.test.js.snap @@ -33,21 +33,31 @@ Object { "Description": "S3 key for asset version \\"2a96a41ef8e6db639865e8dc7826848e60ba75ebdb553c6c9bf2f961ef503deb\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": Object { - "Description": "Artifact hash for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": Object { + "Description": "Artifact hash for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": Object { - "Description": "S3 bucket for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": Object { + "Description": "S3 bucket for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": Object { - "Description": "S3 key for asset version \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": Object { + "Description": "S3 key for asset version \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, }, "Resources": Object { "CloudFrontToS3CloudFrontDistributionCFDistribution7EEEEF4E": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -66,6 +76,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -328,6 +346,101 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, + "CloudFrontToS3SetHttpSecurityHeaders9E6088E2": Object { + "DependsOn": Array [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "CloudFrontToS3SetHttpSecurityHeaders9E6088E2", + }, + }, + "Type": "AWS::Lambda::Version", + }, "CustomResource": Object { "DeletionPolicy": "Delete", "Properties": Object { @@ -354,7 +467,7 @@ Object { "Properties": Object { "Code": Object { "S3Bucket": Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1", }, "S3Key": Object { "Fn::Join": Array [ @@ -367,7 +480,7 @@ Object { "Fn::Split": Array [ "||", Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", }, ], }, @@ -380,7 +493,7 @@ Object { "Fn::Split": Array [ "||", Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", }, ], }, diff --git a/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.expected.json b/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.expected.json index e8e701931..0b4969f90 100644 --- a/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.expected.json +++ b/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.expected.json @@ -166,6 +166,109 @@ } } }, + "CloudFrontToS3CloudFrontOriginAccessIdentity34CC1F91": { + "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", + "Properties": { + "CloudFrontOriginAccessIdentityConfig": { + "Comment": "Access S3 bucket content only through CloudFront" + } + } + }, + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "CloudFrontToS3SetHttpSecurityHeaders9E6088E2": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "CloudFrontToS3SetHttpSecurityHeaders9E6088E2" + } + } + }, "CloudFrontToS3CloudfrontLoggingBucket8350BE9B": { "Type": "AWS::S3::Bucket", "Properties": { @@ -206,14 +309,6 @@ } } }, - "CloudFrontToS3CloudFrontOriginAccessIdentity34CC1F91": { - "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", - "Properties": { - "CloudFrontOriginAccessIdentityConfig": { - "Comment": "Access S3 bucket content only through CloudFront" - } - } - }, "CloudFrontToS3CloudFrontDistributionCFDistribution7EEEEF4E": { "Type": "AWS::CloudFront::Distribution", "Properties": { @@ -234,6 +329,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -279,6 +382,16 @@ "CloudFrontDefaultCertificate": true } } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" + } + ] + } } }, "copyObjHandlerServiceRoleA0ECE649": { @@ -495,7 +608,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1" }, "S3Key": { "Fn::Join": [ @@ -508,7 +621,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -521,7 +634,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -588,17 +701,17 @@ "Type": "String", "Description": "Artifact hash for asset \"2a96a41ef8e6db639865e8dc7826848e60ba75ebdb553c6c9bf2f961ef503deb\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": { "Type": "String", - "Description": "S3 bucket for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 bucket for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": { "Type": "String", - "Description": "S3 key for asset version \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 key for asset version \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": { "Type": "String", - "Description": "Artifact hash for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "Artifact hash for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" } }, "Outputs": { diff --git a/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.ts b/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.ts index 6e8a10593..8bb9d36a2 100644 --- a/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.ts +++ b/source/use_cases/aws-s3-static-website/test/integ.basic-deployment.ts @@ -15,4 +15,4 @@ import * as cdk from '@aws-cdk/core'; import { S3StaticWebsiteStack } from '../lib/s3-static-site-stack'; const app = new cdk.App(); -new S3StaticWebsiteStack(app, 'S3StaticWebsiteStack'); \ No newline at end of file +new S3StaticWebsiteStack(app, 'StaticWebsiteStack'); \ No newline at end of file diff --git a/source/use_cases/aws-serverless-image-handler/package.json b/source/use_cases/aws-serverless-image-handler/package.json index 76fbb415f..b63cb890d 100644 --- a/source/use_cases/aws-serverless-image-handler/package.json +++ b/source/use_cases/aws-serverless-image-handler/package.json @@ -1,6 +1,6 @@ { "name": "@aws-konstruk/aws-serverless-image-handler", - "version": "0.8.0", + "version": "0.8.1", "description": "Use case pattern for deploying a serverless image handler API.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,18 +53,18 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/core": "~1.25.0", - "@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-s3": "~0.8.0", - "@aws-solutions-konstruk/core": "~0.8.0" + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/core": "~1.40.0", + "@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-s3": "~0.8.1", + "@aws-solutions-konstruk/core": "~0.8.1" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -74,14 +74,14 @@ ] }, "peerDependencies": { - "@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-s3": "~0.8.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", - "@aws-cdk/aws-iam": "~1.25.0" + "@aws-solutions-konstruk/aws-cloudfront-apigateway-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-s3": "~0.8.1", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", + "@aws-cdk/aws-iam": "~1.40.0" } } diff --git a/source/use_cases/aws-serverless-image-handler/test/__snapshots__/test.serverless-image-handler.test.js.snap b/source/use_cases/aws-serverless-image-handler/test/__snapshots__/test.serverless-image-handler.test.js.snap index b4d56b094..15dc8b2cc 100644 --- a/source/use_cases/aws-serverless-image-handler/test/__snapshots__/test.serverless-image-handler.test.js.snap +++ b/source/use_cases/aws-serverless-image-handler/test/__snapshots__/test.serverless-image-handler.test.js.snap @@ -3,14 +3,14 @@ exports[`Minimal deployment snapshot test 1`] = ` Object { "Outputs": Object { - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiEndpoint76827D71": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiEndpoint436BA65C": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D", }, "/", ], @@ -51,6 +51,16 @@ Object { "UpdateReplacePolicy": "Retain", }, "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewayCloudFrontDistributionCFDistribution5DCC756A": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -69,6 +79,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion5920FF7F", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -115,7 +133,7 @@ Object { Array [ "https://", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, ".execute-api.", Object { @@ -127,7 +145,7 @@ Object { }, "/", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D", }, "/", ], @@ -192,21 +210,36 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAccount372B2E2D": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersC49E7B59": Object { "DependsOn": Array [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325", ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, "Properties": Object { - "CloudWatchRoleArn": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiCloudWatchRole21DC3987", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325", "Arn", ], }, + "Runtime": "nodejs12.x", }, - "Type": "AWS::ApiGateway::Account", + "Type": "AWS::Lambda::Function", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiCloudWatchRole21DC3987": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -214,7 +247,14 @@ Object { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": Object { - "Service": "apigateway.amazonaws.com", + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", }, }, ], @@ -228,11 +268,7 @@ Object { "Action": Array [ "logs:CreateLogGroup", "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", ], "Effect": "Allow", "Resource": Object { @@ -247,7 +283,7 @@ Object { Object { "Ref": "AWS::AccountId", }, - ":*", + ":log-group:/aws/lambda/*", ], ], }, @@ -255,13 +291,208 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion5920FF7F": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersC49E7B59", + }, + }, + "Type": "AWS::Lambda::Version", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC": Object { + "DependsOn": Array [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3Bucket65CDB50E", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AUTO_WEBP": "No", + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "CORS_ENABLED": "Yes", + "CORS_ORIGIN": "*", + "S3_BUCKET_NAME": Object { + "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + }, + "SOURCE_BUCKETS": Object { + "Fn::Join": Array [ + "", + Array [ + "my-sample-bucket,", + Object { + "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + }, + ], + ], + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", }, ], }, "Type": "AWS::IAM::Role", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*", + ], + "Effect": "Allow", + "Resource": Array [ + Object { + "Fn::GetAtt": Array [ + "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + "Arn", + ], + }, + Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::GetAtt": Array [ + "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + "Arn", + ], + }, + "/*", + ], + ], + }, + ], + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29", + "Roles": Array [ + Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA": Object { "Properties": Object { "BinaryMediaTypes": Array [ "*/*", @@ -271,16 +502,16 @@ Object { "REGIONAL", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi3B1AFDB4ANY1BF514F4": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAB4E809EANYE006B255": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn", ], }, @@ -303,7 +534,7 @@ Object { }, ":", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "/test-invoke-stage/*/", ], @@ -312,12 +543,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi3B1AFDB4ANYA88E54B3": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAB4E809EANY4246CADA": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn", ], }, @@ -340,11 +571,11 @@ Object { }, ":", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "/", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D", }, "/*/", ], @@ -353,7 +584,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYC648EF96": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYBB77827B": Object { "Properties": Object { "AuthorizationType": "AWS_IAM", "HttpMethod": "ANY", @@ -375,7 +606,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn", ], }, @@ -386,53 +617,122 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, }, "Type": "AWS::ApiGateway::Method", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentD7B20DCAf6e8220e21bde23f88e7afaa751339fe": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAccount372B2E2D": Object { "DependsOn": Array [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANY9BF7CFD0", - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4", - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYC648EF96", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", ], - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W45", - "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", - }, - ], - }, - }, "Properties": Object { - "Description": "Automatically created by the RestApi construct", - "RestApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiCloudWatchRole21DC3987", + "Arn", + ], }, }, - "Type": "AWS::ApiGateway::Deployment", + "Type": "AWS::ApiGateway::Account", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiCloudWatchRole21DC3987": Object { "Properties": Object { - "AccessLogSetting": Object { - "DestinationArn": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeployment241D304C32465efa140e67c84d6f2cc66d000275": Object { + "DependsOn": Array [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYF4D41A65", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYBB77827B", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W45", + "reason": "ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource", + }, + ], + }, + }, + "Properties": Object { + "Description": "Automatically created by the RestApi construct", + "RestApiId": Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", + }, + }, + "Type": "AWS::ApiGateway::Deployment", + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D": Object { + "Properties": Object { + "AccessLogSetting": Object { + "DestinationArn": Object { "Fn::GetAtt": Array [ "testserverlessimagehandlerCloudFrontApiGatewayLambdaApiAccessLogGroup75A8AB40", "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentD7B20DCAf6e8220e21bde23f88e7afaa751339fe", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeployment241D304C32465efa140e67c84d6f2cc66d000275", }, "MethodSettings": Array [ Object { @@ -443,21 +743,21 @@ Object { }, ], "RestApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiUsagePlan6B0FADA4": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiUsagePlan24615316": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "Stage": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D", }, "Throttle": Object {}, }, @@ -465,67 +765,27 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938": Object { "Properties": Object { "ParentId": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", "RootResourceId", ], }, "PathPart": "{proxy+}", "RestApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, }, "Type": "AWS::ApiGateway::Resource", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANY9BF7CFD0": Object { - "Properties": Object { - "AuthorizationType": "AWS_IAM", - "HttpMethod": "ANY", - "Integration": Object { - "IntegrationHttpMethod": "POST", - "Type": "AWS_PROXY", - "Uri": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":apigateway:", - Object { - "Ref": "AWS::Region", - }, - ":lambda:path/2015-03-31/functions/", - Object { - "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", - "Arn", - ], - }, - "/invocations", - ], - ], - }, - }, - "ResourceId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4", - }, - "RestApiId": Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", - }, - }, - "Type": "AWS::ApiGateway::Method", - }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi3B1AFDB4ANYproxyC1D1533D": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAB4E809EANYproxy080695EC": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn", ], }, @@ -548,7 +808,7 @@ Object { }, ":", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "/test-invoke-stage/*/{proxy+}", ], @@ -557,12 +817,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi3B1AFDB4ANYproxy2861CE67": Object { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiAB4E809EANYproxy1DD7017D": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn", ], }, @@ -585,11 +845,11 @@ Object { }, ":", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", }, "/", Object { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D", }, "/*/{proxy+}", ], @@ -598,6 +858,46 @@ Object { }, "Type": "AWS::Lambda::Permission", }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYF4D41A65": Object { + "Properties": Object { + "AuthorizationType": "AWS_IAM", + "HttpMethod": "ANY", + "Integration": Object { + "IntegrationHttpMethod": "POST", + "Type": "AWS_PROXY", + "Uri": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":apigateway:", + Object { + "Ref": "AWS::Region", + }, + ":lambda:path/2015-03-31/functions/", + Object { + "Fn::GetAtt": Array [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", + "Arn", + ], + }, + "/invocations", + ], + ], + }, + }, + "ResourceId": Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938", + }, + "RestApiId": Object { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", + }, + }, + "Type": "AWS::ApiGateway::Method", + }, "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662": Object { "DeletionPolicy": "Retain", "Metadata": Object { @@ -678,193 +978,6 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, - "testserverlessimagehandlerLambdaFunction78B3105C": Object { - "DependsOn": Array [ - "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899", - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6", - ], - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", - }, - ], - }, - }, - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3Bucket65CDB50E", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Environment": Object { - "Variables": Object { - "AUTO_WEBP": "No", - "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", - "CORS_ENABLED": "Yes", - "CORS_ORIGIN": "*", - "S3_BUCKET_NAME": Object { - "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - }, - "SOURCE_BUCKETS": Object { - "Fn::Join": Array [ - "", - Array [ - "my-sample-bucket,", - Object { - "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - }, - ], - ], - }, - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6", - "Arn", - ], - }, - "Runtime": "nodejs12.x", - }, - "Type": "AWS::Lambda::Function", - }, - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/lambda/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject*", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - "Arn", - ], - }, - "/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899", - "Roles": Array [ - Object { - "Ref": "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, "testserverlessimagehandlerLambdaS3AccessPolicyD6DC56B2": Object { "Metadata": Object { "cfn_nag": Object { @@ -899,7 +1012,7 @@ Object { "PolicyName": "testserverlessimagehandlerLambdaS3AccessPolicyD6DC56B2", "Roles": Array [ Object { - "Ref": "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6", + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6", }, ], }, diff --git a/source/use_cases/aws-serverless-image-handler/test/integ.basic-deployment.expected.json b/source/use_cases/aws-serverless-image-handler/test/integ.basic-deployment.expected.json index fcdaeb69f..282059c96 100644 --- a/source/use_cases/aws-serverless-image-handler/test/integ.basic-deployment.expected.json +++ b/source/use_cases/aws-serverless-image-handler/test/integ.basic-deployment.expected.json @@ -1,7 +1,199 @@ { "Description": "Integration Test for aws-serverless-image-handler", "Resources": { - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29", + "Roles": [ + { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6" + } + ] + } + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3Bucket65CDB50E" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6", + "Arn" + ] + }, + "Runtime": "nodejs12.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "AUTO_WEBP": "No", + "CORS_ENABLED": "Yes", + "CORS_ORIGIN": "*", + "S3_BUCKET_NAME": { + "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662" + }, + "SOURCE_BUCKETS": { + "Fn::Join": [ + "", + [ + "my-sample-bucket,", + { + "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662" + } + ] + ] + } + } + } + }, + "DependsOn": [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRoleDefaultPolicy9E8AAE29", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaApiAccessLogGroup75A8AB40": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "BinaryMediaTypes": [ @@ -12,21 +204,21 @@ "REGIONAL" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentD7B20DCAf6e8220e21bde23f88e7afaa751339fe": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeployment241D304C32465efa140e67c84d6f2cc66d000275": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANY9BF7CFD0", - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4", - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYC648EF96" + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYF4D41A65", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYBB77827B" ], "Metadata": { "cfn_nag": { @@ -39,11 +231,11 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "AccessLogSetting": { "DestinationArn": { @@ -52,10 +244,10 @@ "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentD7B20DCAf6e8220e21bde23f88e7afaa751339fe" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeployment241D304C32465efa140e67c84d6f2cc66d000275" }, "MethodSettings": [ { @@ -68,28 +260,28 @@ "StageName": "prod" } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiAA086636ANYproxy770FE38C": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi39D5B0E8ANYproxy608045D4": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -112,11 +304,11 @@ }, ":", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "/", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D" }, "/*/{proxy+}" ] @@ -124,13 +316,13 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiAA086636ANYproxy5FAC5F91": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi39D5B0E8ANYproxy3C2F5296": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -153,7 +345,7 @@ }, ":", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "/test-invoke-stage/*/{proxy+}" ] @@ -161,15 +353,15 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxyANY9BF7CFD0": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxyANYF4D41A65": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiproxy5FD5FDA4" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiproxy4612A938" }, "RestApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -190,7 +382,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -201,13 +393,13 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiAA086636ANY706A7345": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYApiPermissiontestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi39D5B0E8ANYE42619BB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -230,11 +422,11 @@ }, ":", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "/", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D" }, "/*/" ] @@ -242,13 +434,13 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiAA086636ANYBCCBE67D": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYApiPermissionTesttestserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi39D5B0E8ANY9D5188F8": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -271,7 +463,7 @@ }, ":", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "/test-invoke-stage/*/" ] @@ -279,18 +471,18 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiANYC648EF96": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiANYBB77827B": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA", "RootResourceId" ] }, "RestApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "AuthorizationType": "AWS_IAM", "Integration": { @@ -311,7 +503,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunction78B3105C", + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionF12AF5FC", "Arn" ] }, @@ -322,27 +514,22 @@ } } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiUsagePlan6B0FADA4": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiUsagePlan24615316": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, "Stage": { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D" }, "Throttle": {} } ] } }, - "testserverlessimagehandlerCloudFrontApiGatewayLambdaApiAccessLogGroup75A8AB40": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiCloudWatchRole21DC3987": { "Type": "AWS::IAM::Role", "Properties": { @@ -409,9 +596,104 @@ } }, "DependsOn": [ - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" ] }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersC49E7B59": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersServiceRole6A96B325" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion5920FF7F": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersC49E7B59" + } + } + }, "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewayCloudfrontLoggingBucket58AA7378": { "Type": "AWS::S3::Bucket", "Properties": { @@ -472,6 +754,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewaySetHttpSecurityHeadersVersion5920FF7F" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -518,7 +808,7 @@ [ "https://", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, ".execute-api.", { @@ -530,7 +820,7 @@ }, "/", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D" }, "/" ] @@ -552,190 +842,13 @@ "CloudFrontDefaultCertificate": true } } - } - }, - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/lambda/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "LambdaFunctionServiceRolePolicy" - } - ] - } - }, - "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject*", - "s3:Abort*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899", - "Roles": [ - { - "Ref": "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6" - } - ] - } - }, - "testserverlessimagehandlerLambdaFunction78B3105C": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "S3Bucket": { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3Bucket65CDB50E" - }, - "S3Key": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters5f752add658f79e0005d882c0bc5a08dc38a14dc55135d974ea1d2226cb28b96S3VersionKeyCF89D2F1" - } - ] - } - ] - } - ] - ] - } - }, - "Handler": "index.handler", - "Role": { - "Fn::GetAtt": [ - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6", - "Arn" - ] - }, - "Runtime": "nodejs12.x", - "Environment": { - "Variables": { - "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", - "AUTO_WEBP": "No", - "CORS_ENABLED": "Yes", - "CORS_ORIGIN": "*", - "S3_BUCKET_NAME": { - "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662" - }, - "SOURCE_BUCKETS": { - "Fn::Join": [ - "", - [ - "my-sample-bucket,", - { - "Ref": "testserverlessimagehandlerExistingLambdaS3S3Bucket9203E662" - } - ] - ] - } - } - } }, - "DependsOn": [ - "testserverlessimagehandlerLambdaFunctionServiceRoleDefaultPolicyD1EA3899", - "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6" - ], "Metadata": { "cfn_nag": { "rules_to_suppress": [ { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" } ] } @@ -846,7 +959,7 @@ "PolicyName": "testserverlessimagehandlerLambdaS3AccessPolicyD6DC56B2", "Roles": [ { - "Ref": "testserverlessimagehandlerLambdaFunctionServiceRole744A1CF6" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaFunctionServiceRole110B3FC6" } ] }, @@ -863,14 +976,14 @@ } }, "Outputs": { - "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiEndpoint76827D71": { + "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiEndpoint436BA65C": { "Value": { "Fn::Join": [ "", [ "https://", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApi2376E6FC" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApi7B1E91FA" }, ".execute-api.", { @@ -882,7 +995,7 @@ }, "/", { - "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaRestApiDeploymentStageprodBE3E04B8" + "Ref": "testserverlessimagehandlerCloudFrontApiGatewayLambdaLambdaRestApiDeploymentStageprodBD57762D" }, "/" ] diff --git a/source/use_cases/aws-serverless-web-app/lib/serverless-backend-stack.ts b/source/use_cases/aws-serverless-web-app/lib/serverless-backend-stack.ts index 20937d0e6..70b57f305 100644 --- a/source/use_cases/aws-serverless-web-app/lib/serverless-backend-stack.ts +++ b/source/use_cases/aws-serverless-web-app/lib/serverless-backend-stack.ts @@ -18,7 +18,6 @@ import * as lambda from '@aws-cdk/aws-lambda'; import { Provider } from '@aws-cdk/custom-resources'; import { CustomResource } from '@aws-cdk/aws-cloudformation'; import { PolicyStatement } from '@aws-cdk/aws-iam'; -import { UserPoolAttribute } from '@aws-cdk/aws-cognito'; import { Cors } from '@aws-cdk/aws-apigateway'; import { AttributeType } from '@aws-cdk/aws-dynamodb'; @@ -37,7 +36,7 @@ export class ServerlessBackendStack extends Stack { }, cognitoUserPoolProps: { userPoolName: 'WileRydes', - autoVerifiedAttributes: [UserPoolAttribute.EMAIL] + userVerification: {} }, apiGatewayProps: { defaultCorsPreflightOptions: { diff --git a/source/use_cases/aws-serverless-web-app/package.json b/source/use_cases/aws-serverless-web-app/package.json index c2b42fe3c..da373f845 100644 --- a/source/use_cases/aws-serverless-web-app/package.json +++ b/source/use_cases/aws-serverless-web-app/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-konstruk/aws-serverless-web-app", - "version": "0.8.0", + "version": "0.8.1", "description": "Use case pattern for deploying a serverless web app.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,24 +28,24 @@ "build+lint+test": "npm run build && npm run lint && npm test && npm run integ-assert" }, "dependencies": { - "@aws-solutions-konstruk/aws-cloudfront-s3": "~0.8.0", - "@aws-solutions-konstruk/aws-cognito-apigateway-lambda": "~0.8.0", - "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.0", - "@aws-cdk/core": "~1.25.0", - "@aws-cdk/aws-lambda": "~1.25.0", - "@aws-cdk/aws-cloudfront": "~1.25.0", - "@aws-cdk/aws-s3": "~1.25.0", - "@aws-cdk/custom-resources": "~1.25.0", - "@aws-cdk/aws-cloudformation": "~1.25.0", - "@aws-cdk/aws-iam": "~1.25.0", - "@aws-cdk/aws-cognito": "~1.25.0", - "@aws-cdk/aws-apigateway": "~1.25.0", - "@aws-cdk/aws-dynamodb": "~1.25.0", - "@aws-solutions-konstruk/core": "~0.8.0", + "@aws-solutions-konstruk/aws-cloudfront-s3": "~0.8.1", + "@aws-solutions-konstruk/aws-cognito-apigateway-lambda": "~0.8.1", + "@aws-solutions-konstruk/aws-lambda-dynamodb": "~0.8.1", + "@aws-cdk/core": "~1.40.0", + "@aws-cdk/aws-lambda": "~1.40.0", + "@aws-cdk/aws-cloudfront": "~1.40.0", + "@aws-cdk/aws-s3": "~1.40.0", + "@aws-cdk/custom-resources": "~1.40.0", + "@aws-cdk/aws-cloudformation": "~1.40.0", + "@aws-cdk/aws-iam": "~1.40.0", + "@aws-cdk/aws-cognito": "~1.40.0", + "@aws-cdk/aws-apigateway": "~1.40.0", + "@aws-cdk/aws-dynamodb": "~1.40.0", + "@aws-solutions-konstruk/core": "~0.8.1", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.25.0", + "@aws-cdk/assert": "~1.40.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, diff --git a/source/use_cases/aws-serverless-web-app/test/__snapshots__/s3-static-site-stack.test.js.snap b/source/use_cases/aws-serverless-web-app/test/__snapshots__/s3-static-site-stack.test.js.snap index 76b778abc..0c577a1dc 100644 --- a/source/use_cases/aws-serverless-web-app/test/__snapshots__/s3-static-site-stack.test.js.snap +++ b/source/use_cases/aws-serverless-web-app/test/__snapshots__/s3-static-site-stack.test.js.snap @@ -41,21 +41,31 @@ Object { "Description": "S3 key for asset version \\"1726e5810ad30312b951166bf153fa8cbc793db9019a7fa8f3440a20d21f3d36\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": Object { - "Description": "Artifact hash for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": Object { + "Description": "Artifact hash for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": Object { - "Description": "S3 bucket for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": Object { + "Description": "S3 bucket for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": Object { - "Description": "S3 key for asset version \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": Object { + "Description": "S3 key for asset version \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, }, "Resources": Object { "CloudFrontToS3CloudFrontDistributionCFDistribution7EEEEF4E": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", + }, + ], + }, + }, "Properties": Object { "DistributionConfig": Object { "DefaultCacheBehavior": Object { @@ -74,6 +84,14 @@ Object { }, "QueryString": false, }, + "LambdaFunctionAssociations": Array [ + Object { + "EventType": "origin-response", + "LambdaFunctionARN": Object { + "Ref": "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE", + }, + }, + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https", }, @@ -336,6 +354,101 @@ Object { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Retain", }, + "CloudFrontToS3SetHttpSecurityHeaders9E6088E2": Object { + "DependsOn": Array [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + "Arn", + ], + }, + "Runtime": "nodejs12.x", + }, + "Type": "AWS::Lambda::Function", + }, + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "edgelambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE": Object { + "Properties": Object { + "FunctionName": Object { + "Ref": "CloudFrontToS3SetHttpSecurityHeaders9E6088E2", + }, + }, + "Type": "AWS::Lambda::Version", + }, "CustomResource": Object { "DeletionPolicy": "Delete", "Properties": Object { @@ -362,7 +475,7 @@ Object { "Properties": Object { "Code": Object { "S3Bucket": Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1", }, "S3Key": Object { "Fn::Join": Array [ @@ -375,7 +488,7 @@ Object { "Fn::Split": Array [ "||", Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", }, ], }, @@ -388,7 +501,7 @@ Object { "Fn::Split": Array [ "||", Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", }, ], }, diff --git a/source/use_cases/aws-serverless-web-app/test/__snapshots__/serverless-backend-stack.test.js.snap b/source/use_cases/aws-serverless-web-app/test/__snapshots__/serverless-backend-stack.test.js.snap index 331872706..7c8428d1b 100644 --- a/source/use_cases/aws-serverless-web-app/test/__snapshots__/serverless-backend-stack.test.js.snap +++ b/source/use_cases/aws-serverless-web-app/test/__snapshots__/serverless-backend-stack.test.js.snap @@ -3,14 +3,14 @@ exports[`default stack 1`] = ` Object { "Outputs": Object { - "RestApiEndpoint0551178A": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiEndpoint02EBBDD6": Object { "Value": Object { "Fn::Join": Array [ "", Array [ "https://", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, ".execute-api.", Object { @@ -22,7 +22,7 @@ Object { }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1", }, "/", ], @@ -43,253 +43,145 @@ Object { "Description": "S3 key for asset version \\"3aa519f176d0d52023f4992f8ada07849f844467dcb0d4dfb94bb3b350a1d791\\"", "Type": "String", }, - "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360ArtifactHash5ED5576F": Object { - "Description": "Artifact hash for asset \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": Object { + "Description": "Artifact hash for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360S3Bucket20EEB389": Object { - "Description": "S3 bucket for asset \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": Object { + "Description": "S3 bucket for asset \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360S3VersionKeyC46EC577": Object { - "Description": "S3 key for asset version \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": Object { + "Description": "S3 key for asset version \\"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": Object { - "Description": "Artifact hash for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360ArtifactHash5ED5576F": Object { + "Description": "Artifact hash for asset \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": Object { - "Description": "S3 bucket for asset \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360S3Bucket20EEB389": Object { + "Description": "S3 bucket for asset \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", "Type": "String", }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": Object { - "Description": "S3 key for asset version \\"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\\"", + "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360S3VersionKeyC46EC577": Object { + "Description": "S3 key for asset version \\"9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360\\"", "Type": "String", }, }, "Resources": Object { - "ApiAccessLogGroupCEA70788": Object { + "CognitoToApiGatewayToLambdaApiAccessLogGroup43A4A269": Object { "DeletionPolicy": "Retain", "Type": "AWS::Logs::LogGroup", "UpdateReplacePolicy": "Retain", }, - "CognitoAuthorizer": Object { + "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99": Object { "Properties": Object { "IdentitySource": "method.request.header.Authorization", "Name": "authorizer", "ProviderARNs": Array [ Object { "Fn::GetAtt": Array [ - "CognitoUserPool53E37E69", + "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1", "Arn", ], }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "Type": "COGNITO_USER_POOLS", }, "Type": "AWS::ApiGateway::Authorizer", }, - "CognitoUserPool53E37E69": Object { + "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1": Object { "Properties": Object { - "AutoVerifiedAttributes": Array [ - "email", - ], - "LambdaConfig": Object {}, + "AdminCreateUserConfig": Object { + "AllowAdminCreateUserOnly": true, + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": Object { + "ExternalId": "ServerlessBackendStackCognitoToApiGatewayToLambdaCognitoUserPool0C465C62", + "SnsCallerArn": Object { + "Fn::GetAtt": Array [ + "CognitoToApiGatewayToLambdaCognitoUserPoolsmsRole62C22F60", + "Arn", + ], + }, + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": Object { "AdvancedSecurityMode": "ENFORCED", }, "UserPoolName": "WileRydes", + "VerificationMessageTemplate": Object { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}", + }, }, "Type": "AWS::Cognito::UserPool", }, - "CognitoUserPoolClient5AB59AE4": Object { + "CognitoToApiGatewayToLambdaCognitoUserPoolClientC6919938": Object { "Properties": Object { "UserPoolId": Object { - "Ref": "CognitoUserPool53E37E69", + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1", }, }, "Type": "AWS::Cognito::UserPoolClient", }, - "CustomResource": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "Bucket": Object { - "Fn::ImportValue": "websiteBucket", - }, - "Client": Object { - "Ref": "CognitoUserPoolClient5AB59AE4", - }, - "Region": Object { - "Ref": "AWS::Region", - }, - "RestApi": Object { - "Fn::Join": Array [ - "", - Array [ - "https://", - Object { - "Ref": "RestApi0C43BF4B", - }, - ".execute-api.", - Object { - "Ref": "AWS::Region", - }, - ".", - Object { - "Ref": "AWS::URLSuffix", - }, - "/", - Object { - "Ref": "RestApiDeploymentStageprod3855DE66", - }, - "/", - ], - ], - }, - "ServiceToken": Object { - "Fn::GetAtt": Array [ - "CustomResourceProviderframeworkonEvent0AA4376C", - "Arn", - ], - }, - "UserPool": Object { - "Ref": "CognitoUserPool53E37E69", - }, - }, - "Type": "AWS::CloudFormation::CustomResource", - "UpdateReplacePolicy": "Delete", - }, - "CustomResourceProviderframeworkonEvent0AA4376C": Object { - "DependsOn": Array [ - "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647", - "CustomResourceProviderframeworkonEventServiceRole7EBC5835", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::Select": Array [ - 0, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", - }, - ], - }, - ], - }, - Object { - "Fn::Select": Array [ - 1, - Object { - "Fn::Split": Array [ - "||", - Object { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19", - }, - ], - }, - ], - }, - ], - ], - }, - }, - "Environment": Object { - "Variables": Object { - "USER_ON_EVENT_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "updateConfigHandler59840941", - "Arn", - ], + "CognitoToApiGatewayToLambdaCognitoUserPoolsmsRole62C22F60": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish", }, - }, - }, - "Handler": "framework.onEvent", - "Role": Object { - "Fn::GetAtt": Array [ - "CustomResourceProviderframeworkonEventServiceRole7EBC5835", - "Arn", ], }, - "Runtime": "nodejs10.x", - "Timeout": 900, }, - "Type": "AWS::Lambda::Function", - }, - "CustomResourceProviderframeworkonEventServiceRole7EBC5835": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ Object { "Action": "sts:AssumeRole", + "Condition": Object { + "StringEquals": Object { + "sts:ExternalId": "ServerlessBackendStackCognitoToApiGatewayToLambdaCognitoUserPool0C465C62", + }, + }, "Effect": "Allow", "Principal": Object { - "Service": "lambda.amazonaws.com", + "Service": "cognito-idp.amazonaws.com", }, }, ], "Version": "2012-10-17", }, - "ManagedPolicyArns": Array [ + "Policies": Array [ Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", + "PolicyDocument": Object { + "Statement": Array [ Object { - "Ref": "AWS::Partition", + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*", }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "updateConfigHandler59840941", - "Arn", - ], - }, + "Version": "2012-10-17", }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647", - "Roles": Array [ - Object { - "Ref": "CustomResourceProviderframeworkonEventServiceRole7EBC5835", + "PolicyName": "sns-publish", }, ], }, - "Type": "AWS::IAM::Policy", + "Type": "AWS::IAM::Role", }, - "LambdaFunctionBF21E41F": Object { + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C": Object { "DependsOn": Array [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B", + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE", + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6", ], "Metadata": Object { "cfn_nag": Object { @@ -351,7 +243,7 @@ Object { "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ - "LambdaFunctionServiceRole0C4CDE0B", + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6", "Arn", ], }, @@ -359,7 +251,7 @@ Object { }, "Type": "AWS::Lambda::Function", }, - "LambdaFunctionServiceRole0C4CDE0B": Object { + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -410,7 +302,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -443,124 +335,31 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE", "Roles": Array [ Object { - "Ref": "LambdaFunctionServiceRole0C4CDE0B", + "Ref": "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6", }, ], }, "Type": "AWS::IAM::Policy", }, - "LambdaRestApiAccount": Object { - "DependsOn": Array [ - "RestApi0C43BF4B", - ], - "Properties": Object { - "CloudWatchRoleArn": Object { - "Fn::GetAtt": Array [ - "LambdaRestApiCloudWatchRoleF339D4E6", - "Arn", - ], - }, - }, - "Type": "AWS::ApiGateway::Account", - }, - "LambdaRestApiCloudWatchRoleF339D4E6": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "apigateway.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "logs:GetLogEvents", - "logs:FilterLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaRestApiCloudWatchRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "LambdaToDynamoDBDynamoTable53C1442D": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "RideId", - "AttributeType": "S", - }, - ], - "BillingMode": "PAY_PER_REQUEST", - "KeySchema": Array [ - Object { - "AttributeName": "RideId", - "KeyType": "HASH", - }, - ], - "SSESpecification": Object { - "SSEEnabled": true, - }, - "TableName": "Rides", - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Retain", - }, - "RestApi0C43BF4B": Object { + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0": Object { "Properties": Object { "EndpointConfiguration": Object { "Types": Array [ "EDGE", ], }, - "Name": "RestApi", + "Name": "LambdaRestApi", }, "Type": "AWS::ApiGateway::RestApi", }, - "RestApiANYA7C1DC94": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiANY53FD6161": Object { "Properties": Object { "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": Object { - "Ref": "CognitoAuthorizer", + "Ref": "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99", }, "HttpMethod": "ANY", "Integration": Object { @@ -581,7 +380,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -592,22 +391,22 @@ Object { }, "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiANYApiPermissionServerlessBackendStackRestApi00D08F58ANYEEE63A3B": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiANYApiPermissionServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYAD0464C2": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -630,11 +429,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1", }, "/*/", ], @@ -643,12 +442,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiANYApiPermissionTestServerlessBackendStackRestApi00D08F58ANY9F8B1D52": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiANYApiPermissionTestServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYC531DE60": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -671,22 +470,91 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "/test-invoke-stage/*/", ], ], }, }, - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", + }, + "CognitoToApiGatewayToLambdaLambdaRestApiAccountD1F8AA14": Object { + "DependsOn": Array [ + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", + ], + "Properties": Object { + "CloudWatchRoleArn": Object { + "Fn::GetAtt": Array [ + "CognitoToApiGatewayToLambdaLambdaRestApiCloudWatchRoleD7E52FBB", + "Arn", + ], + }, + }, + "Type": "AWS::ApiGateway::Account", + }, + "CognitoToApiGatewayToLambdaLambdaRestApiCloudWatchRoleD7E52FBB": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "apigateway.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "logs:GetLogEvents", + "logs:FilterLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaRestApiCloudWatchRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", }, - "RestApiDeployment180EC5030503bead3cacf3da667720719058e886": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiDeployment1E6D5E6682fe19d2bcf96aadbe65fec49213c15c": Object { "DependsOn": Array [ - "RestApiproxyANY1786B242", - "RestApiproxyOPTIONS32C4B154", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", - "RestApiOPTIONS6AA64D2D", + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANY2839789B", + "CognitoToApiGatewayToLambdaLambdaRestApiproxyOPTIONS63FED6E8", + "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA", + "CognitoToApiGatewayToLambdaLambdaRestApiANY53FD6161", + "CognitoToApiGatewayToLambdaLambdaRestApiOPTIONS84242119", ], "Metadata": Object { "cfn_nag": Object { @@ -701,24 +569,24 @@ Object { "Properties": Object { "Description": "Automatically created by the RestApi construct", "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, }, "Type": "AWS::ApiGateway::Deployment", }, - "RestApiDeploymentStageprod3855DE66": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1": Object { "Properties": Object { "AccessLogSetting": Object { "DestinationArn": Object { "Fn::GetAtt": Array [ - "ApiAccessLogGroupCEA70788", + "CognitoToApiGatewayToLambdaApiAccessLogGroup43A4A269", "Arn", ], }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \\"$context.httpMethod $context.resourcePath $context.protocol\\" $context.status $context.responseLength $context.requestId", + "Format": "{\\"requestId\\":\\"$context.requestId\\",\\"ip\\":\\"$context.identity.sourceIp\\",\\"user\\":\\"$context.identity.user\\",\\"caller\\":\\"$context.identity.caller\\",\\"requestTime\\":\\"$context.requestTime\\",\\"httpMethod\\":\\"$context.httpMethod\\",\\"resourcePath\\":\\"$context.resourcePath\\",\\"status\\":\\"$context.status\\",\\"protocol\\":\\"$context.protocol\\",\\"responseLength\\":\\"$context.responseLength\\"}", }, "DeploymentId": Object { - "Ref": "RestApiDeployment180EC5030503bead3cacf3da667720719058e886", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeployment1E6D5E6682fe19d2bcf96aadbe65fec49213c15c", }, "MethodSettings": Array [ Object { @@ -729,13 +597,13 @@ Object { }, ], "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "StageName": "prod", }, "Type": "AWS::ApiGateway::Stage", }, - "RestApiOPTIONS6AA64D2D": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiOPTIONS84242119": Object { "Properties": Object { "AuthorizationType": "NONE", "HttpMethod": "OPTIONS", @@ -767,25 +635,25 @@ Object { ], "ResourceId": Object { "Fn::GetAtt": Array [ - "RestApi0C43BF4B", + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", "RootResourceId", ], }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiUsagePlan6E1C537A": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiUsagePlanBC5A9D9D": Object { "Properties": Object { "ApiStages": Array [ Object { "ApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "Stage": Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1", }, "Throttle": Object {}, }, @@ -793,11 +661,26 @@ Object { }, "Type": "AWS::ApiGateway::UsagePlan", }, - "RestApiproxyANY1786B242": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA": Object { + "Properties": Object { + "ParentId": Object { + "Fn::GetAtt": Array [ + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", + "RootResourceId", + ], + }, + "PathPart": "{proxy+}", + "RestApiId": Object { + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", + }, + }, + "Type": "AWS::ApiGateway::Resource", + }, + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANY2839789B": Object { "Properties": Object { "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": Object { - "Ref": "CognitoAuthorizer", + "Ref": "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99", }, "HttpMethod": "ANY", "Integration": Object { @@ -818,7 +701,7 @@ Object { ":lambda:path/2015-03-31/functions/", Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -828,20 +711,20 @@ Object { }, }, "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, }, "Type": "AWS::ApiGateway::Method", }, - "RestApiproxyANYApiPermissionServerlessBackendStackRestApi00D08F58ANYproxy20E632AA": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANYApiPermissionServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYproxy694ECA33": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -864,11 +747,11 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "/", Object { - "Ref": "RestApiDeploymentStageprod3855DE66", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1", }, "/*/{proxy+}", ], @@ -877,12 +760,12 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyANYApiPermissionTestServerlessBackendStackRestApi00D08F58ANYproxyF3BB47AD": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANYApiPermissionTestServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYproxy29080D5A": Object { "Properties": Object { "Action": "lambda:InvokeFunction", "FunctionName": Object { "Fn::GetAtt": Array [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn", ], }, @@ -905,7 +788,7 @@ Object { }, ":", Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, "/test-invoke-stage/*/{proxy+}", ], @@ -914,22 +797,7 @@ Object { }, "Type": "AWS::Lambda::Permission", }, - "RestApiproxyC95856DD": Object { - "Properties": Object { - "ParentId": Object { - "Fn::GetAtt": Array [ - "RestApi0C43BF4B", - "RootResourceId", - ], - }, - "PathPart": "{proxy+}", - "RestApiId": Object { - "Ref": "RestApi0C43BF4B", - }, - }, - "Type": "AWS::ApiGateway::Resource", - }, - "RestApiproxyOPTIONS32C4B154": Object { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyOPTIONS63FED6E8": Object { "Properties": Object { "AuthorizationType": "NONE", "HttpMethod": "OPTIONS", @@ -960,14 +828,210 @@ Object { }, ], "ResourceId": Object { - "Ref": "RestApiproxyC95856DD", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA", }, "RestApiId": Object { - "Ref": "RestApi0C43BF4B", + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", }, }, "Type": "AWS::ApiGateway::Method", }, + "CustomResource": Object { + "DeletionPolicy": "Delete", + "Properties": Object { + "Bucket": Object { + "Fn::ImportValue": "websiteBucket", + }, + "Client": Object { + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPoolClientC6919938", + }, + "Region": Object { + "Ref": "AWS::Region", + }, + "RestApi": Object { + "Fn::Join": Array [ + "", + Array [ + "https://", + Object { + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", + }, + ".execute-api.", + Object { + "Ref": "AWS::Region", + }, + ".", + Object { + "Ref": "AWS::URLSuffix", + }, + "/", + Object { + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1", + }, + "/", + ], + ], + }, + "ServiceToken": Object { + "Fn::GetAtt": Array [ + "CustomResourceProviderframeworkonEvent0AA4376C", + "Arn", + ], + }, + "UserPool": Object { + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1", + }, + }, + "Type": "AWS::CloudFormation::CustomResource", + "UpdateReplacePolicy": "Delete", + }, + "CustomResourceProviderframeworkonEvent0AA4376C": Object { + "DependsOn": Array [ + "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647", + "CustomResourceProviderframeworkonEventServiceRole7EBC5835", + ], + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "USER_ON_EVENT_FUNCTION_ARN": Object { + "Fn::GetAtt": Array [ + "updateConfigHandler59840941", + "Arn", + ], + }, + }, + }, + "Handler": "framework.onEvent", + "Role": Object { + "Fn::GetAtt": Array [ + "CustomResourceProviderframeworkonEventServiceRole7EBC5835", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + "Timeout": 900, + }, + "Type": "AWS::Lambda::Function", + }, + "CustomResourceProviderframeworkonEventServiceRole7EBC5835": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "ManagedPolicyArns": Array [ + Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + ], + ], + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "updateConfigHandler59840941", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "CustomResourceProviderframeworkonEventServiceRoleDefaultPolicy93CD1647", + "Roles": Array [ + Object { + "Ref": "CustomResourceProviderframeworkonEventServiceRole7EBC5835", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "LambdaToDynamoDBDynamoTable53C1442D": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "AttributeDefinitions": Array [ + Object { + "AttributeName": "RideId", + "AttributeType": "S", + }, + ], + "BillingMode": "PAY_PER_REQUEST", + "KeySchema": Array [ + Object { + "AttributeName": "RideId", + "KeyType": "HASH", + }, + ], + "SSESpecification": Object { + "SSEEnabled": true, + }, + "TableName": "Rides", + }, + "Type": "AWS::DynamoDB::Table", + "UpdateReplacePolicy": "Retain", + }, "updateConfigHandler59840941": Object { "DependsOn": Array [ "updateConfigHandlerServiceRoleDefaultPolicy157F28C3", diff --git a/source/use_cases/aws-serverless-web-app/test/integ.s3-static-website-deployment.expected.json b/source/use_cases/aws-serverless-web-app/test/integ.001-s3-static-website-deployment.expected.json similarity index 74% rename from source/use_cases/aws-serverless-web-app/test/integ.s3-static-website-deployment.expected.json rename to source/use_cases/aws-serverless-web-app/test/integ.001-s3-static-website-deployment.expected.json index f59d7e0df..e8503e711 100644 --- a/source/use_cases/aws-serverless-web-app/test/integ.s3-static-website-deployment.expected.json +++ b/source/use_cases/aws-serverless-web-app/test/integ.001-s3-static-website-deployment.expected.json @@ -166,6 +166,109 @@ } } }, + "CloudFrontToS3CloudFrontOriginAccessIdentity34CC1F91": { + "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", + "Properties": { + "CloudFrontOriginAccessIdentityConfig": { + "Comment": "Access S3 bucket content only through CloudFront" + } + } + }, + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "edgelambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "CloudFrontToS3SetHttpSecurityHeaders9E6088E2": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "CloudFrontToS3SetHttpSecurityHeadersServiceRole6BABDE10" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "CloudFrontToS3SetHttpSecurityHeaders9E6088E2" + } + } + }, "CloudFrontToS3CloudfrontLoggingBucket8350BE9B": { "Type": "AWS::S3::Bucket", "Properties": { @@ -206,14 +309,6 @@ } } }, - "CloudFrontToS3CloudFrontOriginAccessIdentity34CC1F91": { - "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", - "Properties": { - "CloudFrontOriginAccessIdentityConfig": { - "Comment": "Access S3 bucket content only through CloudFront" - } - } - }, "CloudFrontToS3CloudFrontDistributionCFDistribution7EEEEF4E": { "Type": "AWS::CloudFront::Distribution", "Properties": { @@ -234,6 +329,14 @@ }, "QueryString": false }, + "LambdaFunctionAssociations": [ + { + "EventType": "origin-response", + "LambdaFunctionARN": { + "Ref": "CloudFrontToS3SetHttpSecurityHeadersVersion699208AE" + } + } + ], "TargetOriginId": "origin1", "ViewerProtocolPolicy": "redirect-to-https" }, @@ -279,6 +382,16 @@ "CloudFrontDefaultCertificate": true } } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W70", + "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion" + } + ] + } } }, "staticContentHandlerServiceRole3B648F21": { @@ -495,7 +608,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1" }, "S3Key": { "Fn::Join": [ @@ -508,7 +621,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -521,7 +634,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -588,17 +701,17 @@ "Type": "String", "Description": "Artifact hash for asset \"1726e5810ad30312b951166bf153fa8cbc793db9019a7fa8f3440a20d21f3d36\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": { "Type": "String", - "Description": "S3 bucket for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 bucket for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": { "Type": "String", - "Description": "S3 key for asset version \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 key for asset version \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": { "Type": "String", - "Description": "Artifact hash for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "Artifact hash for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" } }, "Outputs": { diff --git a/source/use_cases/aws-serverless-web-app/test/integ.s3-static-website-deployment.ts b/source/use_cases/aws-serverless-web-app/test/integ.001-s3-static-website-deployment.ts similarity index 100% rename from source/use_cases/aws-serverless-web-app/test/integ.s3-static-website-deployment.ts rename to source/use_cases/aws-serverless-web-app/test/integ.001-s3-static-website-deployment.ts diff --git a/source/use_cases/aws-serverless-web-app/test/integ.backend-deployment.expected.json b/source/use_cases/aws-serverless-web-app/test/integ.002-backend-deployment.expected.json similarity index 73% rename from source/use_cases/aws-serverless-web-app/test/integ.backend-deployment.expected.json rename to source/use_cases/aws-serverless-web-app/test/integ.002-backend-deployment.expected.json index b626e9eb7..5c4837a56 100644 --- a/source/use_cases/aws-serverless-web-app/test/integ.backend-deployment.expected.json +++ b/source/use_cases/aws-serverless-web-app/test/integ.002-backend-deployment.expected.json @@ -1,6 +1,6 @@ { "Resources": { - "LambdaFunctionServiceRole0C4CDE0B": { + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -51,7 +51,7 @@ ] } }, - "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { @@ -85,15 +85,15 @@ ], "Version": "2012-10-17" }, - "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "PolicyName": "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE", "Roles": [ { - "Ref": "LambdaFunctionServiceRole0C4CDE0B" + "Ref": "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6" } ] } }, - "LambdaFunctionBF21E41F": { + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { @@ -137,7 +137,7 @@ "Handler": "index.handler", "Role": { "Fn::GetAtt": [ - "LambdaFunctionServiceRole0C4CDE0B", + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6", "Arn" ] }, @@ -152,8 +152,8 @@ } }, "DependsOn": [ - "LambdaFunctionServiceRoleDefaultPolicy126C8897", - "LambdaFunctionServiceRole0C4CDE0B" + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRoleDefaultPolicyCC3D84AE", + "CognitoToApiGatewayToLambdaLambdaFunctionServiceRole921AB2D6" ], "Metadata": { "cfn_nag": { @@ -166,7 +166,12 @@ } } }, - "RestApi0C43BF4B": { + "CognitoToApiGatewayToLambdaApiAccessLogGroup43A4A269": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "EndpointConfiguration": { @@ -174,23 +179,23 @@ "EDGE" ] }, - "Name": "RestApi" + "Name": "LambdaRestApi" } }, - "RestApiDeployment180EC5030503bead3cacf3da667720719058e886": { + "CognitoToApiGatewayToLambdaLambdaRestApiDeployment1E6D5E6682fe19d2bcf96aadbe65fec49213c15c": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "Description": "Automatically created by the RestApi construct" }, "DependsOn": [ - "RestApiproxyANY1786B242", - "RestApiproxyOPTIONS32C4B154", - "RestApiproxyC95856DD", - "RestApiANYA7C1DC94", - "RestApiOPTIONS6AA64D2D" + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANY2839789B", + "CognitoToApiGatewayToLambdaLambdaRestApiproxyOPTIONS63FED6E8", + "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA", + "CognitoToApiGatewayToLambdaLambdaRestApiANY53FD6161", + "CognitoToApiGatewayToLambdaLambdaRestApiOPTIONS84242119" ], "Metadata": { "cfn_nag": { @@ -203,23 +208,23 @@ } } }, - "RestApiDeploymentStageprod3855DE66": { + "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1": { "Type": "AWS::ApiGateway::Stage", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "AccessLogSetting": { "DestinationArn": { "Fn::GetAtt": [ - "ApiAccessLogGroupCEA70788", + "CognitoToApiGatewayToLambdaApiAccessLogGroup43A4A269", "Arn" ] }, - "Format": "$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + "Format": "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"user\":\"$context.identity.user\",\"caller\":\"$context.identity.caller\",\"requestTime\":\"$context.requestTime\",\"httpMethod\":\"$context.httpMethod\",\"resourcePath\":\"$context.resourcePath\",\"status\":\"$context.status\",\"protocol\":\"$context.protocol\",\"responseLength\":\"$context.responseLength\"}" }, "DeploymentId": { - "Ref": "RestApiDeployment180EC5030503bead3cacf3da667720719058e886" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeployment1E6D5E6682fe19d2bcf96aadbe65fec49213c15c" }, "MethodSettings": [ { @@ -232,18 +237,18 @@ "StageName": "prod" } }, - "RestApiOPTIONS6AA64D2D": { + "CognitoToApiGatewayToLambdaLambdaRestApiOPTIONS84242119": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "OPTIONS", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "AuthorizationType": "NONE", "Integration": { @@ -274,30 +279,30 @@ ] } }, - "RestApiproxyC95856DD": { + "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", "RootResourceId" ] }, "PathPart": "{proxy+}", "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" } } }, - "RestApiproxyOPTIONS32C4B154": { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyOPTIONS63FED6E8": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "OPTIONS", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "AuthorizationType": "NONE", "Integration": { @@ -328,13 +333,13 @@ ] } }, - "RestApiproxyANYApiPermissionServerlessBackendStackRestApi00D08F58ANYproxy20E632AA": { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANYApiPermissionServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYproxy694ECA33": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -357,11 +362,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" }, "/*/{proxy+}" ] @@ -369,13 +374,13 @@ } } }, - "RestApiproxyANYApiPermissionTestServerlessBackendStackRestApi00D08F58ANYproxyF3BB47AD": { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANYApiPermissionTestServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYproxy29080D5A": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -398,7 +403,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "/test-invoke-stage/*/{proxy+}" ] @@ -406,19 +411,19 @@ } } }, - "RestApiproxyANY1786B242": { + "CognitoToApiGatewayToLambdaLambdaRestApiproxyANY2839789B": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { - "Ref": "RestApiproxyC95856DD" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiproxy008E09BA" }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": { - "Ref": "CognitoAuthorizer" + "Ref": "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99" }, "Integration": { "IntegrationHttpMethod": "POST", @@ -438,7 +443,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -449,13 +454,13 @@ } } }, - "RestApiANYApiPermissionServerlessBackendStackRestApi00D08F58ANYEEE63A3B": { + "CognitoToApiGatewayToLambdaLambdaRestApiANYApiPermissionServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYAD0464C2": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -478,11 +483,11 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" }, "/*/" ] @@ -490,13 +495,13 @@ } } }, - "RestApiANYApiPermissionTestServerlessBackendStackRestApi00D08F58ANY9F8B1D52": { + "CognitoToApiGatewayToLambdaLambdaRestApiANYApiPermissionTestServerlessBackendStackCognitoToApiGatewayToLambdaLambdaRestApi6BF82CD7ANYC531DE60": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -519,7 +524,7 @@ }, ":", { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "/test-invoke-stage/*/" ] @@ -527,22 +532,22 @@ } } }, - "RestApiANYA7C1DC94": { + "CognitoToApiGatewayToLambdaLambdaRestApiANY53FD6161": { "Type": "AWS::ApiGateway::Method", "Properties": { "HttpMethod": "ANY", "ResourceId": { "Fn::GetAtt": [ - "RestApi0C43BF4B", + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0", "RootResourceId" ] }, "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "AuthorizationType": "COGNITO_USER_POOLS", "AuthorizerId": { - "Ref": "CognitoAuthorizer" + "Ref": "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99" }, "Integration": { "IntegrationHttpMethod": "POST", @@ -562,7 +567,7 @@ ":lambda:path/2015-03-31/functions/", { "Fn::GetAtt": [ - "LambdaFunctionBF21E41F", + "CognitoToApiGatewayToLambdaLambdaFunction555D0B9C", "Arn" ] }, @@ -573,28 +578,23 @@ } } }, - "RestApiUsagePlan6E1C537A": { + "CognitoToApiGatewayToLambdaLambdaRestApiUsagePlanBC5A9D9D": { "Type": "AWS::ApiGateway::UsagePlan", "Properties": { "ApiStages": [ { "ApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "Stage": { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" }, "Throttle": {} } ] } }, - "ApiAccessLogGroupCEA70788": { - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "LambdaRestApiCloudWatchRoleF339D4E6": { + "CognitoToApiGatewayToLambdaLambdaRestApiCloudWatchRoleD7E52FBB": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -649,46 +649,110 @@ ] } }, - "LambdaRestApiAccount": { + "CognitoToApiGatewayToLambdaLambdaRestApiAccountD1F8AA14": { "Type": "AWS::ApiGateway::Account", "Properties": { "CloudWatchRoleArn": { "Fn::GetAtt": [ - "LambdaRestApiCloudWatchRoleF339D4E6", + "CognitoToApiGatewayToLambdaLambdaRestApiCloudWatchRoleD7E52FBB", "Arn" ] } }, "DependsOn": [ - "RestApi0C43BF4B" + "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" ] }, - "CognitoUserPool53E37E69": { + "CognitoToApiGatewayToLambdaCognitoUserPoolsmsRole62C22F60": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "ServerlessBackendStackCognitoToApiGatewayToLambdaCognitoUserPool0C465C62" + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cognito-idp.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "sns-publish" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W11", + "reason": "Allowing * resource on permissions policy since its used by Cognito to send SMS messages via sns:Publish" + } + ] + } + } + }, + "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AutoVerifiedAttributes": [ - "email" - ], - "LambdaConfig": {}, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": { + "ExternalId": "ServerlessBackendStackCognitoToApiGatewayToLambdaCognitoUserPool0C465C62", + "SnsCallerArn": { + "Fn::GetAtt": [ + "CognitoToApiGatewayToLambdaCognitoUserPoolsmsRole62C22F60", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolAddOns": { "AdvancedSecurityMode": "ENFORCED" }, - "UserPoolName": "WileRydes" + "UserPoolName": "WileRydes", + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}" + } } }, - "CognitoUserPoolClient5AB59AE4": { + "CognitoToApiGatewayToLambdaCognitoUserPoolClientC6919938": { "Type": "AWS::Cognito::UserPoolClient", "Properties": { "UserPoolId": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1" } } }, - "CognitoAuthorizer": { + "CognitoToApiGatewayToLambdaCognitoAuthorizerAF023B99": { "Type": "AWS::ApiGateway::Authorizer", "Properties": { "RestApiId": { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "Type": "COGNITO_USER_POOLS", "IdentitySource": "method.request.header.Authorization", @@ -696,7 +760,7 @@ "ProviderARNs": [ { "Fn::GetAtt": [ - "CognitoUserPool53E37E69", + "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1", "Arn" ] } @@ -888,7 +952,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1" }, "S3Key": { "Fn::Join": [ @@ -901,7 +965,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -914,7 +978,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19" + "Ref": "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC" } ] } @@ -959,10 +1023,10 @@ ] }, "UserPool": { - "Ref": "CognitoUserPool53E37E69" + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPool6EE989F1" }, "Client": { - "Ref": "CognitoUserPoolClient5AB59AE4" + "Ref": "CognitoToApiGatewayToLambdaCognitoUserPoolClientC6919938" }, "Region": { "Ref": "AWS::Region" @@ -976,7 +1040,7 @@ [ "https://", { - "Ref": "RestApi0C43BF4B" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, ".execute-api.", { @@ -988,7 +1052,7 @@ }, "/", { - "Ref": "RestApiDeploymentStageprod3855DE66" + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" }, "/" ] @@ -1023,6 +1087,34 @@ "DeletionPolicy": "Retain" } }, + "Outputs": { + "CognitoToApiGatewayToLambdaLambdaRestApiEndpoint02EBBDD6": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" + }, + "/" + ] + ] + } + } + }, "Parameters": { "AssetParameters9a9c398189879e9ca9700ba0658086063d8ee7ccd068043c722c28478c6c4360S3Bucket20EEB389": { "Type": "String", @@ -1048,45 +1140,17 @@ "Type": "String", "Description": "Artifact hash for asset \"3aa519f176d0d52023f4992f8ada07849f844467dcb0d4dfb94bb3b350a1d791\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3Bucket6B4B2C9B": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3Bucket0A1029B1": { "Type": "String", - "Description": "S3 bucket for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 bucket for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9S3VersionKey8971BB19": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061S3VersionKeyFB75FDAC": { "Type": "String", - "Description": "S3 key for asset version \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" + "Description": "S3 key for asset version \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" }, - "AssetParametersf587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9ArtifactHash72EE40C1": { + "AssetParameters4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061ArtifactHash40CCFA64": { "Type": "String", - "Description": "Artifact hash for asset \"f587c683163dea7b70b883fe8f803ffe0622a40e05b3766e08ffa9ed25caabc9\"" - } - }, - "Outputs": { - "RestApiEndpoint0551178A": { - "Value": { - "Fn::Join": [ - "", - [ - "https://", - { - "Ref": "RestApi0C43BF4B" - }, - ".execute-api.", - { - "Ref": "AWS::Region" - }, - ".", - { - "Ref": "AWS::URLSuffix" - }, - "/", - { - "Ref": "RestApiDeploymentStageprod3855DE66" - }, - "/" - ] - ] - } + "Description": "Artifact hash for asset \"4c2988a57571fd4c34de12bae67441541aeea1a59e085f95e5b708922ff45061\"" } } } \ No newline at end of file diff --git a/source/use_cases/aws-serverless-web-app/test/integ.backend-deployment.ts b/source/use_cases/aws-serverless-web-app/test/integ.002-backend-deployment.ts similarity index 100% rename from source/use_cases/aws-serverless-web-app/test/integ.backend-deployment.ts rename to source/use_cases/aws-serverless-web-app/test/integ.002-backend-deployment.ts diff --git a/source/use_cases/aws-serverless-web-app/test/serverless-backend-stack.test.ts b/source/use_cases/aws-serverless-web-app/test/serverless-backend-stack.test.ts index 5c76a4548..c60b47ede 100644 --- a/source/use_cases/aws-serverless-web-app/test/serverless-backend-stack.test.ts +++ b/source/use_cases/aws-serverless-web-app/test/serverless-backend-stack.test.ts @@ -65,11 +65,11 @@ test('check lambda permissions', () => { }, ":", { - Ref: "RestApi0C43BF4B" + Ref: "CognitoToApiGatewayToLambdaLambdaRestApi31103AF0" }, "/", { - Ref: "RestApiDeploymentStageprod3855DE66" + Ref: "CognitoToApiGatewayToLambdaLambdaRestApiDeploymentStageprod743A20E1" }, "/*/" ]