├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-improvements.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .prettierignore ├── .prettierrc.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── architecture.png ├── package-lock.json ├── package.json └── source ├── dashboard.ndjson ├── resources ├── README.md ├── __tests__ │ ├── cl.test.ts │ └── utils.test.ts ├── bin │ └── app.ts ├── cdk.json ├── jest.config.js ├── lib │ ├── cl-demo-ec2-construct.ts │ ├── cl-demo-stack.ts │ ├── cl-jumpbox-construct.ts │ ├── cl-primary-stack.ts │ ├── manifest.json │ ├── resource-retention-aspect.ts │ └── utils.ts ├── package-lock.json ├── package.json └── tsconfig.json ├── run-unit-tests.sh └── services ├── @aws-solutions └── utils │ ├── logger.ts │ ├── metric.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── helper ├── PromiseConstructor.d.ts ├── index.ts ├── package-lock.json ├── package.json └── tsconfig.json ├── transformer ├── PromiseConstructor.d.ts ├── index.ts ├── package-lock.json ├── package.json └── tsconfig.json └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | # don't ever lint node_modules 2 | node_modules 3 | cdk.out 4 | # don't lint build output (make sure it's set to your correct build folder name) 5 | dist 6 | # don't lint nyc coverage output 7 | coverage 8 | *.config.js 9 | *.eslint* 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | parserOptions: { 5 | ecmaVersion: 2021, 6 | }, 7 | plugins: ["@typescript-eslint", "prettier"], 8 | env: { 9 | node: true, 10 | }, 11 | extends: [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/eslint-recommended", 14 | "plugin:@typescript-eslint/recommended", 15 | "prettier", 16 | "plugin:prettier/recommended", 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | 11 | 12 | 13 | **To Reproduce** 14 | 15 | 16 | 17 | **Expected behavior** 18 | 19 | 20 | 21 | **Please complete the following information about the solution:** 22 | 23 | - [ ] Version: [e.g. v1.0.0] 24 | 25 | To get the version of the solution, you can look at the description of the created CloudFormation stack. For example, "_(SO0009) - The AWS CloudFormation template for deployment of the aws-centralized-logging. Version v1.0.0_". You can also find the version from [releases](https://github.com/aws-solutions/aws-centralized-logging/releases) 26 | 27 | - [ ] Region: [e.g. us-east-1] 28 | - [ ] Was the solution modified from the version published on this repository? 29 | - [ ] If the answer to the previous question was yes, are the changes available on GitHub? 30 | - [ ] Have you checked your [service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) for the sevices this solution uses? 31 | - [ ] Were there any errors in the CloudWatch Logs? [How to enable debug mode?](https://docs.aws.amazon.com/solutions/latest/centralized-logging/appendix-d.html) 32 | 33 | **Screenshots** 34 | If applicable, add screenshots to help explain your problem (please **DO NOT include sensitive information**). 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-improvements.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation improvements 3 | about: Suggest a documentation update 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What were you initially searching for in the docs?** 11 | 12 | 13 | **Is this related to an existing part of the documentation? Please share a link** 14 | 15 | **Describe how we could make it clearer** 16 | 17 | **If you have a proposed update, please share it here** -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this solution 4 | title: '' 5 | labels: feature-request, enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | 13 | **Describe the feature you'd like** 14 | 15 | 16 | **Additional context** 17 | 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Test and Compiler files 2 | **test.json 3 | **test.js 4 | 5 | # distribution folders 6 | global-s3-assets 7 | regional-s3-assets 8 | open-source 9 | 10 | # Generated ouputs 11 | dist 12 | coverage 13 | docs 14 | npm-debug.log 15 | *.zip 16 | .scannerwork 17 | *.xml 18 | reports 19 | source/services/@aws-solutions/utils/*/index.js 20 | 21 | # Node dependencies 22 | node_modules 23 | *.js 24 | !jest.config.js 25 | *.d.ts 26 | 27 | # CDK asset staging directory 28 | .cdk.staging 29 | cdk.out 30 | __snapshots__ 31 | 32 | # Misc 33 | .DS_Store 34 | 35 | # IDEs 36 | .idea -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | # .prettierrc or .prettierrc.yaml 2 | arrowParens: "always" 3 | bracketSpacing: true 4 | endOfLine: "lf" 5 | htmlWhitespaceSensitivity: "css" 6 | proseWrap: "preserve" 7 | trailingComma: "es5" 8 | tabWidth: 2 9 | semi: true 10 | singleQuote: false 11 | quoteProps: "as-needed" 12 | printWidth: 80 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [4.0.6] - 2023-10-24 9 | 10 | ### Changed 11 | 12 | - Update dependencies to address [CVE-2023-45133](https://github.com/advisories/GHSA-67hx-6x53-jw92) 13 | 14 | ## [4.0.5] - 2023-09-18 15 | 16 | ### Changed 17 | 18 | - Update lambda runtime to NodeJS 18 19 | - Update dependencies 20 | 21 | 22 | ## [4.0.4] - 2023-07-07 23 | 24 | ### Changed 25 | 26 | - Bug fix 27 | - correct batch size for firhose.putRecordBatch 28 | - Upgrade dependencies 29 | - Enforce [imdsV2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) 30 | 31 | ## [4.0.3] - 2023-04-13 32 | 33 | ### Changed 34 | 35 | - Upgrade CDK to version 2 36 | - Upgrade nodejs version for build pipeline to 16 37 | - Upgrade nodejs version for lambda functions to 16 38 | - Include ClusterSize in deployment metrics 39 | - Upgrade aws-sdk version to mitigate [CVE-2023-0842: xml2js vulnerable to prototype pollution](https://nvd.nist.gov/vuln/detail/CVE-2023-0842) 40 | 41 | ## [4.0.2] - 2022-09-14 42 | 43 | ### Changed 44 | 45 | - updated package versions 46 | - utils logger/metrics moved up to flatten directory hierarchy 47 | 48 | ## [4.0.1] - 2021-12-05 49 | 50 | ### Added 51 | 52 | - support for '+' in admin email address 53 | 54 | ### Changed 55 | 56 | - aws-cdk updated to 1.132.0 57 | - moved generic helpers to utils library, [logger](./source/services/utils/logger), [metrics](./source/services/utils/metrics) 58 | - CloudWatch Logs destinations created with UUID appended to name for uniqueness 59 | 60 | ## [4.0.0] - 2020-12-15 61 | 62 | ### Added 63 | 64 | - VPC with 2 isolated & 2 public subnets 65 | - Elasticsearch domain in isolated subnets 66 | - Kinesis Data Stream and Kinesis Firehose for data streaming 67 | - CloudWatch Logs Destination for cross account/region data streaming 68 | - Windows jumpbox for accessing kibana 69 | - Security group for jumpbox 70 | - Security group for ES and Kinesis resources 71 | 72 | ### Updated 73 | 74 | - Elasticsearch V7.7 75 | - Lambda log event transformer 76 | - AWS CDK constructs for IaC 77 | 78 | ### Removed 79 | 80 | - Spoke templates 81 | - Cross account IAM role for Lambda (cross account streaming now uses CloudWatch Logs Destination) 82 | 83 | ## [3.2.1] - 2020-09-14 84 | 85 | ### Added 86 | 87 | - SNS topic is now encrypted using KMS CMK 88 | - Optional MFA support for Cognito users 89 | 90 | ### Updated 91 | 92 | - Now uses CDK to create deployment templates 93 | - Leverages AWS Solutions Contruct for Lambda/ElasticSearch/Kibana 94 | - Updated to use Amazon Elasticsearch Service v7.7 95 | 96 | ### Removed 97 | 98 | - Demo Access Logging bucket no longer enables versioning 99 | - Removed global egress access from the VPC security group 100 | - Removed all hard-coded logical resource IDs and names to enable multiple stacks to be deployed, such as for testing or migration 101 | 102 | ## [3.2] - 2019-12-18 103 | 104 | ### Added 105 | 106 | - Backward-compatible to v3.0.0 107 | - Includes all v3.0.1 changes 108 | - Do NOT upgrade from v3.0.1 to v3.2 109 | 110 | ## [3.0.1] - 2019-11-29 111 | 112 | ### Added 113 | 114 | - Uses SSM Parameters to retrieve the latest HVM x86_64 AMI 115 | - Block public access to 2 buckets created for demo 116 | - CLFullAccessUserRole replaces CognitoAuthorizedRole. It is associated with the Admin group. Initial user is placed in this group. 117 | - CLReadOnlyAccessRole is added. It provides read-only access to users in UserPoolGroupROAccess. This is the default role for Authenticated users in the pool. 118 | 119 | ### Updated 120 | 121 | - Nodejs8.10 to Nodejs12.x Lambda run time. 122 | - Updated license to Apache License version 2.0 123 | - Corrected Master_Role environmental variable in spoke template to MASTER_ROLE 124 | - Updated demo EC2 instance to T3.MICRO 125 | - Updated Nodejs deprecated buffer() to buffer.from() 126 | - Removed python solution-helper from spoke template and replaced with the Nodejs version used by primary. 127 | - Updated NOTICE.txt for 3rd party modules 128 | - Replaced istanbul (deprecated) with nyc 129 | - ElasticSearch version moved to a mapping parameter 130 | - ElasticSearch cluster mappings consolidated under ElasticSearch for clarity/usability 131 | - Tightened security on IAM roles to specific methods and resources 132 | 133 | ### Removed 134 | 135 | - Unreferenced SolutionHelperRole in demo template 136 | - Unreferenced S3 bucket mapping in demo template 137 | - AMIInfo lookup Lambda 138 | - CognitoUnAuthorizedRole / unauthenticated Cognito access 139 | 140 | ## [0.0.1] - 2019-09-09 141 | 142 | ### Added 143 | 144 | - CHANGELOG template file to fix new pipeline standards 145 | 146 | ### Updated 147 | 148 | - updated buildspec.yml to meet new pipeline build standards 149 | - updated build-s3-dist.sh to meet new pipeline build standards 150 | - updated run-unit-tests.sh for correct references to folders 151 | - updated cloudformation templates to include a bucket for S3 access logs 152 | - updated cloudformation template with correct lambda function environment variable key names 153 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | ## Reporting Bugs/Feature Requests 10 | 11 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 12 | 13 | When filing an issue, please check [existing open](https://github.com/aws-solutions/aws-centralized-logging/issues), or [recently closed](https://github.com/aws-solutions/aws-centralized-logging/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 14 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 15 | 16 | - A reproducible test case or series of steps 17 | - The version of our code being used 18 | - Any modifications you've made relevant to the bug 19 | - Anything unusual about your environment or deployment 20 | 21 | ## Contributing via Pull Requests 22 | 23 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 24 | 25 | 1. You are working against the latest source on the _master_ branch. 26 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 27 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 28 | 29 | To send us a pull request, please: 30 | 31 | 1. Fork the repository. 32 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 33 | 3. Ensure local tests pass. 34 | 4. Commit to your fork using clear commit messages. 35 | 5. Send us a pull request, answering any default questions in the pull request interface. 36 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 37 | 38 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 39 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 40 | 41 | ## Finding contributions to work on 42 | 43 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-solutions/aws-centralized-logging/labels/help%20wanted) issues is a great place to start. 44 | 45 | ## Code of Conduct 46 | 47 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 48 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 49 | opensource-codeofconduct@amazon.com with any additional questions or comments. 50 | 51 | ## Security issue notifications 52 | 53 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 54 | 55 | ## Licensing 56 | 57 | See the [LICENSE](https://github.com/aws-solutions/aws-centralized-logging/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 58 | 59 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 60 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Centralized Logging on AWS 2 | 3 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | Licensed under the Apache License Version 2.0 (the "License"). You may not use this file except 5 | in compliance with the License. A copy of the License is located at http://www.apache.org/licenses/ 6 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, 7 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. See the License for the 8 | specific language governing permissions and limitations under the License. 9 | 10 | ********************** 11 | THIRD PARTY COMPONENTS 12 | ********************** 13 | This software includes third party software subject to the following copyrights: 14 | 15 | aws-sdk under Apache License 2.0 16 | aws-cdk under Apache License 2.0 17 | got under MIT License 18 | uuid under MIT License 19 | winston under MIT License -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Centralized Logging on AWS Solution 2 | **Centralized Logging on AWS has been superseded by the Centralized Logging with OpenSearch [Centralized Logging with OpenSearch](https://aws.amazon.com/solutions/implementations/centralized-logging-with-opensearch/) solution. All existing deployments will continue to work but the solution will no longer be supported and maintained.** 3 | 4 | ## Table of content 5 | 6 | - [Solution Overview](#solution-overview) 7 | - [Architecture](#architecture) 8 | - [Installation](#installing-pre-packaged-solution-template) 9 | - [Customization](#customization) 10 | - [Setup](#setup) 11 | - [Changes](#changes) 12 | - [Unit Test](#unit-test) 13 | - [Build](#build) 14 | - [Deploy](#deploy) 15 | - [Sample Scenario](#sample-scenario) 16 | - [File Structure](#file-structure) 17 | - [License](#license) 18 | 19 | ## Solution Overview 20 | 21 | Centralized Logging on AWS is a reference implementation that provides a foundation for logging to a centralized account. Customers can leverage the solution to index CloudTrail Logs, CW Logs, VPC Flow Logs on an Amazon OpenSearch Service domain. The logs can then be searched on different fields. 22 | 23 | This solution gives you a turnkey environment to begin logging and analyzing your AWS environment and applications. Additionally, if you are looking to 24 | 25 | - collect logs from multiple AWS accounts and organizations 26 | - collect logs from multiple regions 27 | - a single pane view for log analysis and visualization 28 | 29 | then you can get all this with this 1-click deployment solution. 30 | 31 | This solution uses Amazon OpenSearch Service (successor to Amazon Elasticsearch Service) and Kibana, an analytics and visualization platform that is integrated with Amazon OpenSearch Service, that results in a unified view of all the log events. 32 | 33 | ## Architecture 34 | 35 | The Centralized Logging on AWS solution contains the following components: **log ingestion**, **log indexing**, and **visualization**. You must deploy the AWS CloudFormation template in the AWS account where you intend to store your log data. 36 | 37 | 38 | 39 | ## Customization 40 | 41 | - Prerequisite: Node.js>=16 | npm >= 8 42 | 43 | ### Setup 44 | 45 | Clone the repository and run the following commands to install dependencies, format and lint as per the project standards 46 | 47 | ``` 48 | npm ci 49 | npm run prettier-format 50 | npm run lint 51 | ``` 52 | 53 | ### Changes 54 | 55 | You may make any needed change as per your requirement. If you want to customize the Centralized Logging on AWS opinionated defaults, you can modify the [solution manifest file](./source/resources/lib/manifest.json). You can also control sending solution usage metrics to aws-solutions, from the manifest file. 56 | 57 | ``` 58 | "solutionVersion": "%%VERSION%%", #provide a valid value eg. v1.0 59 | "sendMetric": "Yes", 60 | ``` 61 | 62 | ### Unit Test 63 | 64 | You can run unit tests with the following command from the root of the project 65 | 66 | ``` 67 | npm run test 68 | ``` 69 | 70 | ### Build 71 | 72 | You can build lambda binaries with the following command from the root of the project 73 | 74 | ``` 75 | npm run build 76 | ``` 77 | 78 | ### Deploy 79 | 80 | Run the following command from the root of the project. Deploys all the primary solution components needed for Centralized Logging on AWS. **Deploy in Primary Account** 81 | 82 | ``` 83 | cd source/resources 84 | npm ci 85 | ``` 86 | 87 | ``` 88 | npm run cdk-bootstrap -- --profile 89 | npm run cdk-synth 90 | npm run cdk-deploy -- CL-PrimaryStack --parameters AdminEmail= --parameters SpokeAccounts= --parameters JumpboxKey= --parameters JumpboxDeploy='Yes' --profile 91 | ``` 92 | 93 | _Note:_ for PROFILE_NAME, substitute the name of an AWS CLI profile that contains appropriate credentials for deploying in your preferred region. 94 | 95 | ## Sample Scenario (Enabling CloudWatch logging on Elasticsearch domain) 96 | 97 | The default deployment uses opinionated values as setup in [solution manifest file](./source/resources/lib/manifest.json). In this scenario let's say we want to enable CloudWatch logging for ES domain. 98 | 99 | You would need to update the **ESDomain** resource in cl-primary-stack.ts as below: 100 | 101 | ``` 102 | logging: { 103 | slowSearchLogEnabled: true, 104 | appLogEnabled: true, 105 | slowIndexLogEnabled: true, 106 | }, 107 | ``` 108 | 109 | ## File structure 110 | 111 | Centralized Logging on AWS solution consists of: 112 | 113 | - cdk constructs to generate needed resources 114 | - helper for bootstrapping purposes like creating CloudWatch Logs Destinations 115 | - transformer to translate kinesis data stream records into Elasticsearch documents 116 | 117 |
118 | |-config_files                    [ config files for prettier, eslint etc. ]
119 | |-architecture.png                [ solution architecture diagram ]
120 | |-source/
121 |   |dashboard.ndjson               [ sample dashboard for demo ]  
122 |   |run-unit-test.sh               [ script to run unit tests ]
123 |   |-resources
124 |     |-bin/
125 |       |-app.ts                    [ entry point for CDK app ]
126 |     |-__tests__/                  [ unit tests for CDK constructs ] 
127 |     |-lib/
128 |       |-cl-demo-ec2-construct.ts  [ CDK construct for demo web server resource ]
129 |       |-cl-demo-stack.ts          [ CDK construct for demo stack]
130 |       |-cl-jumpbox-construct.ts   [ CDK construct for windows jumpbox resource ]  
131 |       |-cl-primary-stack.ts       [ CDK construct for primary stack and related resources ]
132 |       |-utils.ts                  [ utilities for generic functionalities across CDK constructs ]   
133 |       |-manifest.json             [ manifest file for CDK resources ]
134 |     |-config_files                [ tsconfig, jest.config.js, package.json etc. ]
135 |   |-services/
136 |     |-@aws-solutions/utils/       [ library with generic utility functions for microservice ]
137 |     |-helper/                     [ lambda backed helper custom resource to help with solution launch/update/delete ]
138 |     |-transformer/                [ microservice to translate kinesis records into es documents ]
139 | 
140 | 141 | ## License 142 | 143 | See license [here](./LICENSE.txt) 144 | 145 | 146 | --- 147 | 148 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 149 | 150 | 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 151 | 152 | ``` 153 | http://www.apache.org/licenses/LICENSE-2.0 154 | ``` 155 | 156 | or in the ["license"](./LICENSE.txt) 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. 157 | -------------------------------------------------------------------------------- /architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-solutions/aws-centralized-logging/e4e4ea88fb64141ffe59e2d2c75775b6513ae4af/architecture.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-centralized-logging", 3 | "version": "4.0.6", 4 | "description": "Centralized Logging on AWS", 5 | "scripts": { 6 | "lint": "./node_modules/eslint/bin/eslint.js . --ext .ts", 7 | "prettier-format": "./node_modules/prettier/bin-prettier.js --config .prettierrc.yml '**/*.ts' --write", 8 | "build:helper": "cd source/services/helper && npm run build:all", 9 | "build:transformer": "cd source/services/transformer && npm run build:all", 10 | "build": "npm run build:helper && npm run build:transformer", 11 | "test": "cd source && chmod +x run-unit-tests.sh && ./run-unit-tests.sh" 12 | }, 13 | "author": "aws-solutions", 14 | "license": "Apache-2.0", 15 | "devDependencies": { 16 | "@types/node": "^20.3.1", 17 | "@types/uuid": "^9.0.1", 18 | "@typescript-eslint/eslint-plugin": "^6.8.0", 19 | "@typescript-eslint/parser": "^6.8.0", 20 | "eslint": "^8.43.0", 21 | "eslint-config-prettier": "^9.0.0", 22 | "eslint-plugin-prettier": "^5.0.1", 23 | "prettier": "^3.0.3", 24 | "typescript": "^5.1.3", 25 | "aws-cdk": "^2.68.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /source/dashboard.ndjson: -------------------------------------------------------------------------------- 1 | {"attributes":{"fields":"[{\"name\":\"@log_group\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@log_group.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@log_group\"}}},{\"name\":\"@log_stream\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@log_stream.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@log_stream\"}}},{\"name\":\"@message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@message.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@message\"}}},{\"name\":\"@owner\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@owner.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"@owner\"}}},{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"account_id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"account_id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"account_id\"}}},{\"name\":\"action\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"action.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"action\"}}},{\"name\":\"additionalEventData.AuthenticationMethod\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.AuthenticationMethod.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.AuthenticationMethod\"}}},{\"name\":\"additionalEventData.CipherSuite\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.CipherSuite.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.CipherSuite\"}}},{\"name\":\"additionalEventData.LoginTo\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.LoginTo.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.LoginTo\"}}},{\"name\":\"additionalEventData.MFAUsed\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.MFAUsed.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.MFAUsed\"}}},{\"name\":\"additionalEventData.MobileVersion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.MobileVersion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.MobileVersion\"}}},{\"name\":\"additionalEventData.SignatureVersion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.SignatureVersion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.SignatureVersion\"}}},{\"name\":\"additionalEventData.bytesTransferredIn\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"additionalEventData.bytesTransferredOut\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"additionalEventData.x-amz-id-2\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additionalEventData.x-amz-id-2.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"additionalEventData.x-amz-id-2\"}}},{\"name\":\"agent\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"agent\"}}},{\"name\":\"apiVersion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"apiVersion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"apiVersion\"}}},{\"name\":\"authuser\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"authuser.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"authuser\"}}},{\"name\":\"awsRegion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"awsRegion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"awsRegion\"}}},{\"name\":\"bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"date\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"date.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"date\"}}},{\"name\":\"dstaddr\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dstaddr.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"dstaddr\"}}},{\"name\":\"dstport\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"end\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"errorCode\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"errorCode.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"errorCode\"}}},{\"name\":\"errorMessage\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"errorMessage.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"errorMessage\"}}},{\"name\":\"eventCategory\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventCategory.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventCategory\"}}},{\"name\":\"eventID\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventID.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventID\"}}},{\"name\":\"eventName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventName\"}}},{\"name\":\"eventSource\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventSource.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventSource\"}}},{\"name\":\"eventTime\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"eventType\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventType.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventType\"}}},{\"name\":\"eventVersion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"eventVersion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"eventVersion\"}}},{\"name\":\"host\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"host\"}}},{\"name\":\"id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"id\"}}},{\"name\":\"ident\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ident.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"ident\"}}},{\"name\":\"interface_id\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"interface_id.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"interface_id\"}}},{\"name\":\"log_status\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"log_status.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"log_status\"}}},{\"name\":\"managementEvent\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"protocol\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"readOnly\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"recipientAccountId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"recipientAccountId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"recipientAccountId\"}}},{\"name\":\"referrer\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"referrer.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"referrer\"}}},{\"name\":\"request\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"request\"}}},{\"name\":\"requestID\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"requestID.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"requestID\"}}},{\"name\":\"requestParameters\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"requestParameters.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"requestParameters\"}}},{\"name\":\"resources.ARN\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resources.ARN.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"resources.ARN\"}}},{\"name\":\"resources.accountId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resources.accountId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"resources.accountId\"}}},{\"name\":\"resources.type\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resources.type.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"resources.type\"}}},{\"name\":\"responseElements\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"responseElements.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"responseElements\"}}},{\"name\":\"serviceEventDetails.snapshotId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"serviceEventDetails.snapshotId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"serviceEventDetails.snapshotId\"}}},{\"name\":\"sessionCredentialFromConsole\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sessionCredentialFromConsole.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"sessionCredentialFromConsole\"}}},{\"name\":\"sharedEventID\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sharedEventID.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"sharedEventID\"}}},{\"name\":\"sourceIPAddress\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sourceIPAddress.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"sourceIPAddress\"}}},{\"name\":\"srcaddr\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":3,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"srcaddr.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"srcaddr\"}}},{\"name\":\"srcport\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"start\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"status\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tlsDetails.cipherSuite\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tlsDetails.cipherSuite.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"tlsDetails.cipherSuite\"}}},{\"name\":\"tlsDetails.clientProvidedHostHeader\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tlsDetails.clientProvidedHostHeader.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"tlsDetails.clientProvidedHostHeader\"}}},{\"name\":\"tlsDetails.tlsVersion\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tlsDetails.tlsVersion.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"tlsDetails.tlsVersion\"}}},{\"name\":\"type\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"type.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"type\"}}},{\"name\":\"userAgent\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userAgent.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userAgent\"}}},{\"name\":\"userIdentity.accessKeyId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.accessKeyId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.accessKeyId\"}}},{\"name\":\"userIdentity.accountId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.accountId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.accountId\"}}},{\"name\":\"userIdentity.arn\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.arn.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.arn\"}}},{\"name\":\"userIdentity.identityProvider\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.identityProvider.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.identityProvider\"}}},{\"name\":\"userIdentity.invokedBy\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.invokedBy.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.invokedBy\"}}},{\"name\":\"userIdentity.principalId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.principalId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.principalId\"}}},{\"name\":\"userIdentity.sessionContext.attributes.creationDate\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"userIdentity.sessionContext.attributes.mfaAuthenticated\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.attributes.mfaAuthenticated.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.attributes.mfaAuthenticated\"}}},{\"name\":\"userIdentity.sessionContext.ec2RoleDelivery\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.ec2RoleDelivery.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.ec2RoleDelivery\"}}},{\"name\":\"userIdentity.sessionContext.sessionIssuer.accountId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.sessionIssuer.accountId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.sessionIssuer.accountId\"}}},{\"name\":\"userIdentity.sessionContext.sessionIssuer.arn\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.sessionIssuer.arn.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.sessionIssuer.arn\"}}},{\"name\":\"userIdentity.sessionContext.sessionIssuer.principalId\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.sessionIssuer.principalId.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.sessionIssuer.principalId\"}}},{\"name\":\"userIdentity.sessionContext.sessionIssuer.type\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.sessionIssuer.type.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.sessionIssuer.type\"}}},{\"name\":\"userIdentity.sessionContext.sessionIssuer.userName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.sessionContext.sessionIssuer.userName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.sessionContext.sessionIssuer.userName\"}}},{\"name\":\"userIdentity.type\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.type.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.type\"}}},{\"name\":\"userIdentity.userName\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"userIdentity.userName.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"userIdentity.userName\"}}},{\"name\":\"version\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","timeFieldName":"timestamp","title":"cwl*"},"id":"b72dad40-4d4c-11ec-bcce-3f4b1c5e311c","migrationVersion":{"index-pattern":"7.6.0"},"references":[],"type":"index-pattern","updated_at":"2021-11-24T18:57:13.928Z","version":"WzE4NywxXQ=="} 2 | {"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[],"title":"CW-All Data","version":1},"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","migrationVersion":{"search":"7.4.0"},"references":[{"id":"b72dad40-4d4c-11ec-bcce-3f4b1c5e311c","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","updated_at":"2021-11-24T17:48:25.946Z","version":"WzE2MCwxXQ=="} 3 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"Top 10 Api Sources","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"eventSource.keyword\",\"orderBy\":\"_key\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100}},\"title\":\"Top 10 Api Sources\"}"},"id":"6bcabb50-4d55-11ec-b460-5772f5062857","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:36:21.765Z","version":"WzE3NywxXQ=="} 4 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"Top 10 Access Key Ids","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"userIdentity.accessKeyId.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"UserIdentity AccessKeyId\"}}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"Count\"},\"title\":\"Top 10 Access Key Ids\"}"},"id":"db311a70-4d55-11ec-b460-5772f5062857","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:39:28.663Z","version":"WzE3OSwxXQ=="} 5 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"Top 10 Account Ids","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"account_id.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Account Id\"}}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\",\"row\":false},\"title\":\"Top 10 Account Ids\"}"},"id":"34196b10-4d56-11ec-bcce-3f4b1c5e311c","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:41:57.824Z","version":"WzE4MSwxXQ=="} 6 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"Top 10 AWS Regions","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"awsRegion.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"AWS Region\"}}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\"},\"title\":\"Top 10 AWS Regions\"}"},"id":"65287840-4d56-11ec-afa8-9fe54e15bce6","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:43:20.131Z","version":"WzE4MywxXQ=="} 7 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"PacketCount By Source","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"Packet Count\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"srcaddr.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Source Address\"}}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"Packet Count\"},\"title\":\"PacketCount By Source\"}"},"id":"ba1bc520-4d4f-11ec-9168-077f704f5d1a","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:26:49.602Z","version":"WzE3NCwxXQ=="} 8 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"PacketStatus By Source","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"packets\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"srcaddr.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":10,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"action.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":2,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":false,\"truncate\":100}},\"title\":\"PacketStatus By Source\"}"},"id":"9b8ab670-4d59-11ec-b460-5772f5062857","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T19:06:19.863Z","version":"WzE4OCwxXQ=="} 9 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"PacketsStatus","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"area\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"packets\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"action.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"timestamp\",\"timeRange\":{\"from\":\"now-15m\",\"to\":\"now\"},\"useNormalizedEsInterval\":true,\"scaleMetricValues\":false,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}],\"params\":{\"type\":\"line\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Sum of packets\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"area\",\"mode\":\"normal\",\"data\":{\"label\":\"Sum of packets\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"interpolate\":\"linear\",\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"}},\"title\":\"PacketsStatus\"}"},"id":"b840c6c0-4d53-11ec-b460-5772f5062857","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:24:11.052Z","version":"WzE3MSwxXQ=="} 10 | {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"savedSearchRefName":"search_0","title":"HttpStatus","uiStateJSON":"{}","version":1,"visState":"{\"type\":\"pie\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"status\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}],\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":true,\"values\":true,\"last_level\":true,\"truncate\":100}},\"title\":\"HttpStatus\"}"},"id":"993088e0-4d50-11ec-9168-077f704f5d1a","migrationVersion":{"visualization":"7.7.0"},"references":[{"id":"b9abbab0-4d4e-11ec-9168-077f704f5d1a","name":"search_0","type":"search"}],"type":"visualization","updated_at":"2021-11-24T18:01:50.446Z","version":"WzE2NSwxXQ=="} 11 | {"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.7.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"ecd19bb6-5b50-4b36-8fdc-d9caeae8bbcc\"},\"panelIndex\":\"ecd19bb6-5b50-4b36-8fdc-d9caeae8bbcc\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"f1bc3f1f-2812-4018-9698-3bc9ccfb5994\"},\"panelIndex\":\"f1bc3f1f-2812-4018-9698-3bc9ccfb5994\",\"embeddableConfig\":{},\"panelRefName\":\"panel_1\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":10,\"i\":\"bd12ad1c-9733-46ef-80e4-5ed0f068cba4\"},\"panelIndex\":\"bd12ad1c-9733-46ef-80e4-5ed0f068cba4\",\"embeddableConfig\":{},\"panelRefName\":\"panel_2\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":10,\"i\":\"3c196825-7884-4c8d-93d1-76bdb6e3b069\"},\"panelIndex\":\"3c196825-7884-4c8d-93d1-76bdb6e3b069\",\"embeddableConfig\":{},\"panelRefName\":\"panel_3\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":0,\"y\":40,\"w\":24,\"h\":15,\"i\":\"09bb01d6-687d-4e90-88d5-1b2d8178cb81\"},\"panelIndex\":\"09bb01d6-687d-4e90-88d5-1b2d8178cb81\",\"embeddableConfig\":{},\"panelRefName\":\"panel_4\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":24,\"y\":25,\"w\":24,\"h\":15,\"i\":\"bb313830-deaf-4c10-b665-8fcb474093ed\"},\"panelIndex\":\"bb313830-deaf-4c10-b665-8fcb474093ed\",\"embeddableConfig\":{},\"panelRefName\":\"panel_5\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":0,\"y\":25,\"w\":24,\"h\":15,\"i\":\"f2fe6aa5-aed5-4a6e-a50a-47d304d0fc4b\"},\"panelIndex\":\"f2fe6aa5-aed5-4a6e-a50a-47d304d0fc4b\",\"embeddableConfig\":{\"title\":\"PacketsStatus\",\"colors\":{\"ACCEPT\":\"#64B0C8\",\"REJECT\":\"#BF1B00\"},\"vis\":{\"colors\":{\"ACCEPT\":\"#447EBC\",\"REJECT\":\"#BF1B00\"}}},\"title\":\"PacketsStatus\",\"panelRefName\":\"panel_6\"},{\"version\":\"7.7.0\",\"gridData\":{\"x\":24,\"y\":40,\"w\":24,\"h\":15,\"i\":\"8d1e6b81-61dc-4bf2-8e0c-d4d8e8a06bd4\"},\"panelIndex\":\"8d1e6b81-61dc-4bf2-8e0c-d4d8e8a06bd4\",\"embeddableConfig\":{},\"panelRefName\":\"panel_7\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"now-15m","timeRestore":true,"timeTo":"now","title":"Basic","version":1},"id":"056abf40-4d5a-11ec-b460-5772f5062857","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"6bcabb50-4d55-11ec-b460-5772f5062857","name":"panel_0","type":"visualization"},{"id":"db311a70-4d55-11ec-b460-5772f5062857","name":"panel_1","type":"visualization"},{"id":"34196b10-4d56-11ec-bcce-3f4b1c5e311c","name":"panel_2","type":"visualization"},{"id":"65287840-4d56-11ec-afa8-9fe54e15bce6","name":"panel_3","type":"visualization"},{"id":"ba1bc520-4d4f-11ec-9168-077f704f5d1a","name":"panel_4","type":"visualization"},{"id":"9b8ab670-4d59-11ec-b460-5772f5062857","name":"panel_5","type":"visualization"},{"id":"b840c6c0-4d53-11ec-b460-5772f5062857","name":"panel_6","type":"visualization"},{"id":"993088e0-4d50-11ec-9168-077f704f5d1a","name":"panel_7","type":"visualization"}],"type":"dashboard","updated_at":"2021-11-24T20:20:00.325Z","version":"WzE5NSwxXQ=="} 12 | {"exportedCount":11,"missingRefCount":0,"missingReferences":[]} -------------------------------------------------------------------------------- /source/resources/README.md: -------------------------------------------------------------------------------- 1 | # Centralized Logging on AWS CDK Project 2 | 3 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 4 | 5 | ## Useful commands 6 | 7 | - `npm run build` compile typescript to js 8 | - `npm run watch` watch for changes and compile 9 | - `npm run test` perform the jest unit tests 10 | - `cdk deploy` deploy this stack to your default AWS account/region 11 | - `cdk diff` compare deployed stack with current state 12 | - `cdk synth` emits the synthesized CloudFormation template 13 | -------------------------------------------------------------------------------- /source/resources/__tests__/cl.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import "@aws-cdk/assert/jest"; 5 | import { CLPrimary } from "../lib/cl-primary-stack"; 6 | import { App, Stack } from "aws-cdk-lib"; 7 | 8 | describe("==Primary Stack Tests==", () => { 9 | const app = new App(); 10 | const stack: Stack = new CLPrimary(app, "CL-PrimaryStack"); 11 | 12 | describe("Test resources", () => { 13 | test("snapshot test", () => { 14 | expect(stack).toMatchSnapshot(); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /source/resources/__tests__/utils.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import "@aws-cdk/assert/jest"; 5 | import { App, Stack } from "aws-cdk-lib"; 6 | import * as s3 from "aws-cdk-lib/aws-s3"; 7 | 8 | import { applyCfnNagSuppressRules } from "../lib/utils"; 9 | import { ResourcePart } from "@aws-cdk/assert"; 10 | 11 | test("validate cfn_nag suppressions are added", () => { 12 | const app = new App(); 13 | const stack = new Stack(app, "TestStack"); 14 | 15 | const cfnBucket = new s3.CfnBucket(stack, "TestBucket"); 16 | 17 | // Add individual suppression 18 | applyCfnNagSuppressRules(cfnBucket, [ 19 | { 20 | id: "W1", 21 | reason: "This should be ignored", 22 | }, 23 | ]); 24 | expect(stack).toHaveResourceLike( 25 | "AWS::S3::Bucket", 26 | { 27 | Metadata: { 28 | cfn_nag: { 29 | rules_to_suppress: [ 30 | { 31 | id: "W1", 32 | reason: "This should be ignored", 33 | }, 34 | ], 35 | }, 36 | }, 37 | }, 38 | ResourcePart.CompleteDefinition 39 | ); 40 | 41 | // Add multiple suppressions (one of which is an overwrite) 42 | applyCfnNagSuppressRules(cfnBucket, [ 43 | { 44 | id: "W1", 45 | reason: "Reason for warning 1", 46 | }, 47 | { 48 | id: "W2", 49 | reason: "Reason for warning 2", 50 | }, 51 | { 52 | id: "W3", 53 | reason: "Reason for warning 3", 54 | }, 55 | ]); 56 | 57 | expect(stack).toHaveResource("AWS::S3::Bucket"); 58 | 59 | expect(stack).toHaveResourceLike( 60 | "AWS::S3::Bucket", 61 | { 62 | Metadata: { 63 | cfn_nag: { 64 | rules_to_suppress: [ 65 | { 66 | id: "W1", 67 | reason: "Reason for warning 1", 68 | }, 69 | { 70 | id: "W2", 71 | reason: "Reason for warning 2", 72 | }, 73 | { 74 | id: "W3", 75 | reason: "Reason for warning 3", 76 | }, 77 | ], 78 | }, 79 | }, 80 | }, 81 | ResourcePart.CompleteDefinition 82 | ); 83 | }); 84 | -------------------------------------------------------------------------------- /source/resources/bin/app.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { App, DefaultStackSynthesizer } from "aws-cdk-lib"; 5 | import { CLPrimary } from "../lib/cl-primary-stack"; 6 | 7 | const app = new App(); 8 | 9 | new CLPrimary(app, "CL-PrimaryStack", { 10 | synthesizer: new DefaultStackSynthesizer({ 11 | generateBootstrapVersionRule: false, 12 | }), 13 | }); 14 | -------------------------------------------------------------------------------- /source/resources/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node bin/app.ts", 3 | "context": { 4 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /source/resources/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Automatically clear mock calls and instances between every test 3 | clearMocks: false, 4 | 5 | // The directory where Jest should output its coverage files 6 | coverageDirectory: "coverage", 7 | 8 | // An array of regexp pattern strings used to skip coverage collection 9 | coveragePathIgnorePatterns: ["/node_modules/"], 10 | 11 | // An object that configures minimum threshold enforcement for coverage results 12 | coverageThreshold: { 13 | global: { 14 | // branches: 80, 15 | functions: 80, 16 | lines: 80, 17 | statements: 80, 18 | }, 19 | }, 20 | 21 | // An array of directory names to be searched recursively up from the requiring module's location 22 | moduleDirectories: ["node_modules"], 23 | 24 | // An array of file extensions your modules use 25 | moduleFileExtensions: ["ts", "json", "jsx", "js", "tsx", "node"], 26 | 27 | // Automatically reset mock state between every test 28 | resetMocks: true, 29 | 30 | // The glob patterns Jest uses to detect test files 31 | testMatch: ["**/?(*.)+(spec|test).[t]s?(x)"], 32 | 33 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 34 | testPathIgnorePatterns: ["/node_modules/"], 35 | 36 | // A map from regular expressions to paths to transformers 37 | transform: { 38 | "^.+\\.(t|j)sx?$": "ts-jest", 39 | }, 40 | 41 | // Indicates whether each individual test should be reported during the run 42 | verbose: true, 43 | 44 | coverageReporters: ["text", ["lcov", { projectRoot: "../../" }]], 45 | 46 | // This option allows the use of a custom results processor. 47 | testResultsProcessor: "jest-sonar-reporter", 48 | }; 49 | -------------------------------------------------------------------------------- /source/resources/lib/cl-demo-ec2-construct.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * @description 6 | * This is EC2 construct for WebServer resource 7 | * @author @aws-solutions 8 | */ 9 | 10 | import { Stack, RemovalPolicy, CfnResource } from "aws-cdk-lib"; 11 | import { Construct } from "constructs"; 12 | import { 13 | Vpc, 14 | Instance, 15 | InstanceType, 16 | InitFile, 17 | InitService, 18 | InitServiceRestartHandle, 19 | CloudFormationInit, 20 | MachineImage, 21 | AmazonLinuxVirt, 22 | AmazonLinuxGeneration, 23 | AmazonLinuxCpuType, 24 | SecurityGroup, 25 | Peer, 26 | Port, 27 | InitPackage, 28 | } from "aws-cdk-lib/aws-ec2"; 29 | import { 30 | LogGroup, 31 | RetentionDays, 32 | CfnSubscriptionFilter, 33 | } from "aws-cdk-lib/aws-logs"; 34 | import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam"; 35 | import manifest from "./manifest.json"; 36 | import { cfn_suppress_rules, applyCfnNagSuppressRules } from "./utils"; 37 | 38 | /** 39 | * @interface 40 | * @description web server interface 41 | */ 42 | interface IEC2Demo { 43 | /** 44 | * @description destination arn for log streaming 45 | * @type {string} 46 | */ 47 | destination: string; 48 | /** 49 | * @description vpc for creating demo resources 50 | * @type {Vpc} 51 | */ 52 | demoVpc: Vpc; 53 | } 54 | /** 55 | * @class 56 | * @description web server resources construct 57 | * @property {string} region of deployment 58 | */ 59 | export class EC2Demo extends Construct { 60 | readonly region: string; 61 | readonly publicIp: string; 62 | constructor(scope: Construct, id: string, props: IEC2Demo) { 63 | super(scope, id); 64 | 65 | const stack = Stack.of(this); 66 | 67 | this.region = stack.region; // Returns the AWS::Region for this stack (or the literal value if known) 68 | 69 | /** 70 | * @description security group for web server 71 | * @type {SecurityGroup} 72 | */ 73 | const demoSg: SecurityGroup = new SecurityGroup(this, "DemoSG", { 74 | vpc: props.demoVpc, 75 | }); 76 | demoSg.addIngressRule(Peer.anyIpv4(), Port.tcp(80), "allow HTTP traffic"); 77 | // cfn_nag suppress rule 78 | applyCfnNagSuppressRules(demoSg.node.defaultChild as CfnResource, [ 79 | cfn_suppress_rules.W5, 80 | cfn_suppress_rules.W2, 81 | cfn_suppress_rules.W9, 82 | cfn_suppress_rules.W40, 83 | ]); 84 | 85 | /** 86 | * @description log group for web server 87 | * @type {LogGroup} 88 | */ 89 | const ec2Lg: LogGroup = new LogGroup(this, "EC2LogGroup", { 90 | removalPolicy: RemovalPolicy.DESTROY, 91 | retention: RetentionDays.ONE_WEEK, 92 | }); 93 | 94 | const handle: InitServiceRestartHandle = new InitServiceRestartHandle(); 95 | 96 | /** 97 | * @description cloudformation init configuration for web server 98 | * @type {CloudFormationInit} 99 | */ 100 | const init: CloudFormationInit = CloudFormationInit.fromElements( 101 | InitPackage.yum("httpd", { serviceRestartHandles: [handle] }), 102 | InitPackage.yum("php", { serviceRestartHandles: [handle] }), 103 | InitPackage.yum("amazon-cloudwatch-agent", { 104 | serviceRestartHandles: [handle], 105 | }), 106 | InitFile.fromObject("/tmp/cw-config.json", { //NOSONAR 107 | agent: { 108 | run_as_user: "root", 109 | }, 110 | logs: { 111 | logs_collected: { 112 | files: { 113 | collect_list: [ 114 | { 115 | file_path: "/var/log/httpd/access_log", 116 | log_group_name: ec2Lg.logGroupName, 117 | log_stream_name: "{instance_id}/apache.log", 118 | timezone: "UTC", 119 | }, 120 | ], 121 | }, 122 | }, 123 | }, 124 | }), 125 | InitFile.fromString( 126 | "/var/www/html/index.php", 127 | `AWS CloudFormation sample PHP application'; 129 | ?>`, 130 | { 131 | mode: "000644", 132 | owner: "apache", 133 | group: "apache", 134 | serviceRestartHandles: [handle], 135 | } 136 | ), 137 | InitService.enable("httpd", { 138 | enabled: true, 139 | ensureRunning: true, 140 | serviceRestartHandle: handle, 141 | }) 142 | ); 143 | 144 | /** 145 | * @description web server instance 146 | * @type {Instance} 147 | */ 148 | const demoEC2: Instance = new Instance(this, "DemoEC2", { 149 | vpc: props.demoVpc, 150 | instanceType: new InstanceType(manifest.jumpboxInstanceType), 151 | machineImage: MachineImage.latestAmazonLinux({ 152 | virtualization: AmazonLinuxVirt.HVM, 153 | generation: AmazonLinuxGeneration.AMAZON_LINUX_2, 154 | cpuType: AmazonLinuxCpuType.X86_64, 155 | }), 156 | init: init, 157 | allowAllOutbound: true, 158 | securityGroup: demoSg, 159 | requireImdsv2: true, 160 | }); 161 | 162 | demoEC2.addUserData( 163 | "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop", 164 | "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/tmp/cw-config.json -s", 165 | "curl 127.0.0.1" 166 | ); 167 | demoEC2.addToRolePolicy( 168 | new PolicyStatement({ 169 | effect: Effect.ALLOW, 170 | sid: "LogWrite", 171 | actions: ["logs:Create*", "logs:PutLogEvents"], 172 | resources: [ec2Lg.logGroupArn], 173 | }) 174 | ); 175 | this.publicIp = demoEC2.instancePublicIp; 176 | 177 | new CfnSubscriptionFilter(this, "WebServerSubscription", { 178 | destinationArn: props.destination, 179 | filterPattern: 180 | "[host, ident, authuser, date, request, status, bytes, referrer, agent]", 181 | logGroupName: ec2Lg.logGroupName, 182 | }); 183 | 184 | applyCfnNagSuppressRules(ec2Lg.node.findChild("Resource") as CfnResource, [ 185 | cfn_suppress_rules.W84, 186 | ]); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /source/resources/lib/cl-demo-stack.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * @description 6 | * Demo Stack for Centralized Logging on AWS 7 | * @author @aws-solutions 8 | */ 9 | 10 | import { 11 | CfnMapping, 12 | CfnOutput, 13 | CfnParameter, 14 | CfnResource, 15 | Fn, 16 | NestedStack, 17 | NestedStackProps, 18 | RemovalPolicy, 19 | Stack 20 | } from "aws-cdk-lib"; 21 | import { Construct } from "constructs"; 22 | import { 23 | FlowLog, 24 | FlowLogDestination, 25 | FlowLogResourceType, 26 | FlowLogTrafficType, 27 | SubnetType, 28 | Vpc 29 | } from "aws-cdk-lib/aws-ec2"; 30 | import { Effect, PolicyStatement, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam"; 31 | import { CfnSubscriptionFilter, LogGroup, RetentionDays } from "aws-cdk-lib/aws-logs"; 32 | import { Trail } from "aws-cdk-lib/aws-cloudtrail"; 33 | import { BlockPublicAccess, Bucket, BucketEncryption } from "aws-cdk-lib/aws-s3"; 34 | import { EC2Demo } from "./cl-demo-ec2-construct"; 35 | import { applyCfnNagSuppressRules, cfn_suppress_rules } from "./utils"; 36 | import manifest from "./manifest.json"; 37 | 38 | /** 39 | * @class 40 | * @description demo stack 41 | * @property {string} account id 42 | * @property {string} region of deployment 43 | */ 44 | export class CLDemo extends NestedStack { 45 | readonly account: string; 46 | readonly region: string; 47 | /** 48 | * @constructor 49 | * @param {Construct} scope parent of the construct 50 | * @param {string} id unique identifier for the object 51 | * @param {NestedStackProps} props props for the construct 52 | */ 53 | constructor(scope: Construct, id: string, props?: NestedStackProps) { 54 | super(scope, id, props); 55 | const stack = Stack.of(this); 56 | 57 | this.account = stack.account; // Returns the AWS::AccountId for this stack (or the literal value if known) 58 | this.region = stack.region; // Returns the AWS::Region for this stack (or the literal value if known) 59 | 60 | //============================================================================================= 61 | // Parameters 62 | //============================================================================================= 63 | /** 64 | * @description parameter for CW Logs Destination Arn 65 | * @type {CfnParameter} 66 | */ 67 | const cwLogsDestinationArn: CfnParameter = new CfnParameter( 68 | this, 69 | "CWDestinationParm", 70 | { 71 | type: "String", 72 | } 73 | ); 74 | 75 | //============================================================================================= 76 | // Metadata 77 | //============================================================================================= 78 | this.templateOptions.metadata = { 79 | "AWS::CloudFormation::Interface": { 80 | ParameterGroups: [ 81 | { 82 | Label: { default: "Destination Configuration" }, 83 | Parameters: [cwLogsDestinationArn.logicalId], 84 | }, 85 | ], 86 | ParameterLabels: { 87 | [cwLogsDestinationArn.logicalId]: { 88 | default: "CloudWatch Logs Destination Arn for Log Streaming", 89 | }, 90 | }, 91 | }, 92 | }; 93 | 94 | this.templateOptions.description = `(${manifest.solutionId}D) - The AWS CloudFormation template for deployment of the ${manifest.solutionName}. Version ${manifest.solutionVersion}`; 95 | this.templateOptions.templateFormatVersion = manifest.templateVersion; 96 | 97 | //============================================================================================= 98 | // Map 99 | //============================================================================================= 100 | new CfnMapping(this, "EC2", { 101 | mapping: { Instance: { Type: "t3.micro" } }, 102 | }); 103 | 104 | new CfnMapping(this, "FilterPatternLookup", { 105 | mapping: { 106 | Common: { 107 | Pattern: 108 | "[host, ident, authuser, date, request, status, bytes, referrer, agent]", 109 | }, 110 | CloudTrail: { 111 | Pattern: "", 112 | }, 113 | FlowLogs: { 114 | Pattern: 115 | '[version, account_id, interface_id, srcaddr != "-", dstaddr != "-", srcport != "-", dstport != "-", protocol, packets, bytes, start, end, action, log_status]', 116 | }, 117 | Lambda: { 118 | Pattern: '[timestamp=*Z, request_id="*-*", event]', 119 | }, 120 | SpaceDelimited: { 121 | Pattern: "[]", 122 | }, 123 | Other: { 124 | Pattern: "", 125 | }, 126 | }, 127 | }); 128 | 129 | //============================================================================================= 130 | // Resources 131 | //============================================================================================= 132 | 133 | /** 134 | * @description demo vpc with 1 public subnet 135 | * @type {Vpc} 136 | */ 137 | const demoVPC: Vpc = new Vpc(this, "DemoVPC", { 138 | cidr: "10.0.1.0/26", //NOSONAR 139 | natGateways: 0, 140 | vpnGateway: false, 141 | subnetConfiguration: [ 142 | { 143 | cidrMask: 28, 144 | name: "PublicSubnet", 145 | subnetType: SubnetType.PUBLIC, 146 | }, 147 | ], 148 | }); 149 | demoVPC.applyRemovalPolicy(RemovalPolicy.DESTROY); 150 | demoVPC.publicSubnets.forEach((subnet) => { 151 | applyCfnNagSuppressRules(subnet.node.defaultChild as CfnResource, [ 152 | cfn_suppress_rules.W33, 153 | ]); 154 | }); 155 | 156 | //=================== 157 | // FlowLog resources 158 | //=================== 159 | /** 160 | * @description log group for VPC flow logs 161 | * @type {LogGroup} 162 | */ 163 | const flowLg: LogGroup = new LogGroup(this, "VPCFlowLogGroup", { 164 | removalPolicy: RemovalPolicy.DESTROY, 165 | retention: RetentionDays.ONE_WEEK, 166 | }); 167 | 168 | /** 169 | * @description iam role for flow logs 170 | * @type {Role} 171 | */ 172 | const flowRole: Role = new Role(this, "flowRole", { 173 | assumedBy: new ServicePrincipal("vpc-flow-logs.amazonaws.com"), 174 | }); 175 | 176 | /** 177 | * @description demo flow logs 178 | * @type {FlowLog} 179 | */ 180 | new FlowLog(this, "DemoFlowLog", { 181 | resourceType: FlowLogResourceType.fromVpc(demoVPC), 182 | trafficType: FlowLogTrafficType.ALL, 183 | destination: FlowLogDestination.toCloudWatchLogs(flowLg, flowRole), 184 | }); 185 | 186 | new CfnSubscriptionFilter(this, "FlowLogSubscription", { 187 | destinationArn: cwLogsDestinationArn.valueAsString, 188 | filterPattern: Fn.findInMap("FilterPatternLookup", "FlowLogs", "Pattern"), 189 | logGroupName: flowLg.logGroupName, 190 | }); 191 | 192 | //==================== 193 | // WebServer resources 194 | //==================== 195 | /** 196 | * @description ec2 web server resources 197 | * @type {EC2Demo} 198 | */ 199 | const ec2: EC2Demo = new EC2Demo(this, "WebServer", { 200 | destination: cwLogsDestinationArn.valueAsString, 201 | demoVpc: demoVPC, 202 | }); 203 | 204 | //===================== 205 | // CloudTrail resources 206 | //===================== 207 | /** 208 | * @description log group for CloudTrail 209 | * @type {LogGroup} 210 | */ 211 | const cloudtrailLg: LogGroup = new LogGroup(this, "CloudTrailLogGroup", { 212 | removalPolicy: RemovalPolicy.DESTROY, 213 | retention: RetentionDays.ONE_WEEK, 214 | }); 215 | 216 | /** 217 | * @description bucket for CloudTrail 218 | * @type {Bucket} 219 | */ 220 | const trailBucket: Bucket = new Bucket(this, "TrailBucket", { //NOSONAR 221 | encryption: BucketEncryption.S3_MANAGED, 222 | enforceSSL: true, 223 | blockPublicAccess: BlockPublicAccess.BLOCK_ALL, 224 | }); 225 | trailBucket.addToResourcePolicy( 226 | new PolicyStatement({ 227 | effect: Effect.ALLOW, 228 | principals: [new ServicePrincipal("cloudtrail.amazonaws.com")], 229 | sid: "CloudTrailRead", 230 | actions: ["s3:GetBucketAcl"], 231 | resources: [trailBucket.bucketArn], 232 | }) 233 | ); 234 | trailBucket.addToResourcePolicy( 235 | new PolicyStatement({ 236 | effect: Effect.ALLOW, 237 | principals: [new ServicePrincipal("cloudtrail.amazonaws.com")], 238 | sid: "CloudTrailWrite", 239 | actions: ["s3:PutObject"], 240 | resources: [`${trailBucket.bucketArn}/AWSLogs/${this.account}/*`], 241 | }) 242 | ); 243 | 244 | /** 245 | * @description demo trail 246 | * @type {Trail} 247 | */ 248 | new Trail(this, "demoTrail", { 249 | bucket: trailBucket, 250 | cloudWatchLogGroup: cloudtrailLg, 251 | isMultiRegionTrail: false, 252 | sendToCloudWatchLogs: true, 253 | includeGlobalServiceEvents: true, 254 | }); 255 | 256 | new CfnSubscriptionFilter(this, "CloudTrailSubscription", { 257 | destinationArn: cwLogsDestinationArn.valueAsString, 258 | filterPattern: Fn.findInMap( 259 | "FilterPatternLookup", 260 | "CloudTrail", 261 | "Pattern" 262 | ), 263 | logGroupName: cloudtrailLg.logGroupName, 264 | }); 265 | 266 | //============================================================================================= 267 | // cfn_nag suppress rules 268 | //============================================================================================= 269 | applyCfnNagSuppressRules(trailBucket.node.defaultChild as CfnResource, [ 270 | cfn_suppress_rules.W35, 271 | ]); 272 | 273 | applyCfnNagSuppressRules(flowLg.node.findChild("Resource") as CfnResource, [ 274 | cfn_suppress_rules.W84, 275 | ]); 276 | 277 | applyCfnNagSuppressRules( 278 | cloudtrailLg.node.findChild("Resource") as CfnResource, 279 | [cfn_suppress_rules.W84] 280 | ); 281 | 282 | //============================================================================================= 283 | // Output 284 | //============================================================================================= 285 | new CfnOutput(this, "Destination Arn", { 286 | description: "CloudWatch Logs destination arn", 287 | value: cwLogsDestinationArn.valueAsString, 288 | }); 289 | 290 | new CfnOutput(this, "URL", { 291 | description: "URL for demo web server", 292 | value: `http://${ec2.publicIp}`, 293 | }); 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /source/resources/lib/cl-jumpbox-construct.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * @description 6 | * This is Jumpbox construct for Centralized Logging on AWS Solution 7 | * @author @aws-solutions 8 | */ 9 | 10 | import { Stack, CfnCondition, CfnResource } from "aws-cdk-lib"; 11 | import { Construct } from "constructs"; 12 | import { 13 | Instance, 14 | InstanceType, 15 | MachineImage, 16 | WindowsVersion, 17 | Vpc, 18 | SecurityGroup, 19 | ISubnet, 20 | Port, 21 | Peer, 22 | } from "aws-cdk-lib/aws-ec2"; 23 | import manifest from "./manifest.json"; 24 | import { applyCfnNagSuppressRules, cfn_suppress_rules } from "./utils"; 25 | 26 | interface IJumpbox { 27 | /** 28 | * @description vpc to launch jumpbox 29 | * @type {Vpc} 30 | */ 31 | vpc: Vpc; 32 | /** 33 | * @description public subnets to launch jumpbox 34 | * @type {ISubnet[]} 35 | */ 36 | subnets: ISubnet[]; 37 | /** 38 | * @description ssh key for jumpbox 39 | * @type {string} 40 | */ 41 | keyname: string; 42 | /** 43 | * @description deploy jumpbox 44 | * @type {CfnCondition} 45 | */ 46 | deploy: CfnCondition; 47 | } 48 | /** 49 | * @class 50 | * @description web server resources construct 51 | * @property {string} region of deployment 52 | */ 53 | export class Jumpbox extends Construct { 54 | readonly region: string; 55 | constructor(scope: Construct, id: string, props: IJumpbox) { 56 | super(scope, id); 57 | 58 | const stack = Stack.of(this); 59 | 60 | this.region = stack.region; // Returns the AWS::Region for this stack (or the literal value if known) 61 | 62 | //========================================================================= 63 | // Resource 64 | //========================================================================= 65 | /** 66 | * @description security group for jumpbox 67 | * @type {SecurityGroup} 68 | */ 69 | const sg: SecurityGroup = new SecurityGroup(this, "JumpboxSG", { 70 | vpc: props.vpc, 71 | allowAllOutbound: false, 72 | }); 73 | sg.addEgressRule(Peer.anyIpv4(), Port.tcp(80), "allow outbound https"); 74 | sg.addEgressRule(Peer.anyIpv4(), Port.tcp(443), "allow outbound https"); 75 | applyCfnNagSuppressRules(sg.node.defaultChild as CfnResource, [ 76 | cfn_suppress_rules.W5, 77 | ]); 78 | (sg.node.defaultChild as CfnResource).cfnOptions.condition = props.deploy; 79 | 80 | /** 81 | * @description jumpbox instance 82 | * @type {Instance} 83 | */ 84 | const jumpbox: Instance = new Instance(this, "JumpboxEC2", { 85 | vpc: props.vpc, 86 | instanceType: new InstanceType(manifest.jumpboxInstanceType), 87 | machineImage: MachineImage.latestWindows( 88 | WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_FULL_BASE 89 | ), 90 | securityGroup: sg, 91 | vpcSubnets: { subnets: props.subnets }, 92 | keyName: props.keyname, 93 | requireImdsv2: true, 94 | }); 95 | (jumpbox.node.defaultChild as CfnResource).cfnOptions.condition = 96 | props.deploy; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /source/resources/lib/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "solutionId": "SO0009", 3 | "metricsEndpoint": "https://metrics.awssolutionsbuilder.com/generic", 4 | "solutionName": "%%SOLUTION_NAME%%", 5 | "templateVersion": "2010-09-09", 6 | "solutionVersion": "%%VERSION%%", 7 | "sendMetric": "Yes", 8 | "streamName": "CL-KinesisStream", 9 | "firehoseName": "CL-Firehose", 10 | "cwDestinationName": "CL-Destination", 11 | "firehosePolicy": "CL-Firehose-Policy", 12 | "jumpboxInstanceType": "t3.micro", 13 | "esdomain": { 14 | "vpcCIDR": "10.0.0.0/16", 15 | "masterNodes": 3 16 | }, 17 | "kinesisDataStream": { 18 | "shard": 1, 19 | "retentionInHrs": 24 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /source/resources/lib/resource-retention-aspect.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CfnResource, IAspect } from "aws-cdk-lib"; 5 | import { IConstruct } from "constructs"; 6 | import { applyRetentionPolicy } from "./utils"; 7 | 8 | /** 9 | * @description cdk aspect to apply deletion policy 10 | */ 11 | export class ResourceRetentionAspect implements IAspect { 12 | public visit(node: IConstruct) { 13 | if (node instanceof CfnResource) { 14 | applyRetentionPolicy(node); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /source/resources/lib/utils.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /** 5 | * @description 6 | * Utils for cdk constructs 7 | * @author @aws-solutions 8 | */ 9 | 10 | import { Resource, CfnResource, RemovalPolicy } from "aws-cdk-lib"; 11 | 12 | interface CfnNagSuppression { 13 | id: string; 14 | reason: string; 15 | } 16 | 17 | export function applyRetentionPolicy(resource: Resource | CfnResource) { 18 | if (resource) { 19 | if (resource instanceof Resource) 20 | resource = resource.node.defaultChild as CfnResource; 21 | resource.applyRemovalPolicy(RemovalPolicy.RETAIN); 22 | } 23 | } 24 | 25 | export function applyDependsOn( 26 | dependee: Resource | CfnResource, 27 | parent: Resource 28 | ) { 29 | if (dependee) { 30 | if (dependee instanceof Resource) 31 | dependee = dependee.node.defaultChild as CfnResource; 32 | dependee.addDependency(parent.node.defaultChild as CfnResource); 33 | } 34 | } 35 | 36 | export function applyCfnNagSuppressRules( 37 | resource: CfnResource, 38 | suppressions: CfnNagSuppression[] 39 | ) { 40 | let rules = []; 41 | 42 | if (suppressions instanceof Array) 43 | for (const suppression of suppressions) { 44 | rules.push({ id: suppression.id, reason: suppression.reason }); 45 | } 46 | 47 | if (resource.cfnOptions.metadata?.cfn_nag) { 48 | // If the CfnResource already contains some suppressions, we don't want to erase them. 49 | const existingRules = 50 | resource.cfnOptions.metadata.cfn_nag.rules_to_suppress; 51 | rules = [...existingRules, ...rules]; 52 | } 53 | 54 | // It's possible that multiple constructs try to add the same suppression. 55 | // We only keep one occurrence (last) of each. 56 | // Based on https://stackoverflow.com/a/56768137 57 | const uniqueRules = [ 58 | ...new Map(rules.map((rule) => [rule.id, rule])).values(), 59 | ]; 60 | 61 | resource.cfnOptions.metadata = { 62 | cfn_nag: { 63 | rules_to_suppress: uniqueRules, 64 | }, 65 | }; 66 | } 67 | 68 | /** 69 | * @description common cfn_nag suppress rules 70 | */ 71 | export const cfn_suppress_rules: { [key: string]: CfnNagSuppression } = { 72 | W2: { 73 | id: "W2", 74 | reason: "Security group is a demo resource, allows CIDR open to world", 75 | }, 76 | W5: { 77 | id: "W5", 78 | reason: "Security group allows outbound traffic for http[s]", 79 | }, 80 | W9: { 81 | id: "W9", 82 | reason: 83 | "Security group is a demo web server, inbound access needed, CIDR not /32", 84 | }, 85 | W11: { 86 | id: "W11", 87 | reason: "Cognito actions do not allow resource level permissions", 88 | }, 89 | W12: { 90 | id: "W12", 91 | reason: "* needed, actions do no support resource level permissions", 92 | }, 93 | W28: { 94 | id: "W28", 95 | reason: "OpenSearch service uses customer provided domain name", 96 | }, 97 | W33: { 98 | id: "W33", 99 | reason: "Subnet allows public ip for jumpbox and demo web server", 100 | }, 101 | W35: { 102 | id: "W35", 103 | reason: 104 | "Access logging disabled on the bucket as its a logging bucket or a demo resource", 105 | }, 106 | W40: { 107 | id: "W40", 108 | reason: 109 | "Security group is a demo resource, egress with allow all IP Protocol", 110 | }, 111 | W51: { 112 | id: "W51", 113 | reason: "Bucket allows permissions for log delivery", 114 | }, 115 | W58: { 116 | id: "W58", 117 | reason: 118 | "CloudWatch logs write permissions added with managed role AWSLambdaBasicExecutionRole", 119 | }, 120 | W76: { 121 | id: "W76", 122 | reason: "IAM policy verified", 123 | }, 124 | W84: { 125 | id: "W84", 126 | reason: 127 | "Log group is encrypted using the CloudWatch server-side encryption keys (AWS Managed Keys)", 128 | }, 129 | W89: { 130 | id: "W89", 131 | reason: 132 | "Not a valid use case for Lambda functions to be deployed inside a VPC", 133 | }, 134 | W92: { 135 | id: "W92", 136 | reason: "Not a valid use case for Lambda reserved concurrency", 137 | }, 138 | }; 139 | -------------------------------------------------------------------------------- /source/resources/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "centralized-logging", 3 | "version": "4.0.2", 4 | "license": "Apache-2.0", 5 | "bin": { 6 | "app": "bin/app.js" 7 | }, 8 | "scripts": { 9 | "pretest": "npm ci", 10 | "test": "./node_modules/jest/bin/jest.js --coverage ./__tests__", 11 | "cdk-bootstrap": "./node_modules/aws-cdk/bin/cdk bootstrap", 12 | "cdk-deploy": "./node_modules/aws-cdk/bin/cdk deploy", 13 | "cdk-destroy": "./node_modules/aws-cdk/bin/cdk destroy", 14 | "cdk-synth": "./node_modules/aws-cdk/bin/cdk synth", 15 | "coverage": "npm ci && ./node_modules/jest/bin/jest.js --coverage ./__tests__" 16 | }, 17 | "devDependencies": { 18 | "@aws-cdk/assert": "^2.68.0", 19 | "@types/jest": "^29.5.2", 20 | "@types/node": "^20.3.1", 21 | "aws-cdk": "^2.85.0", 22 | "jest": "^29.5.0", 23 | "jest-sonar-reporter": "^2.0.0", 24 | "ts-node": "^10.9.1", 25 | "ts-jest": "^29.0.5", 26 | "typescript": "^5.1.3" 27 | }, 28 | "jestSonar": { 29 | "reportPath": "coverage", 30 | "reportFile": "cdk-resources-test-report.xml", 31 | "indent": 4 32 | }, 33 | "overrides": { 34 | "semver": "^7.5.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /source/resources/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ES2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 5 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 6 | "lib": [ 7 | "DOM", 8 | "ES2018" 9 | ] /* Specify library files to be included in the compilation. */, 10 | "declaration": false /* Generates corresponding '.d.ts' file. */, 11 | "noEmit": true, 12 | "outDir": "./dist", 13 | "types": ["jest", "node"], 14 | "removeComments": true /* Do not emit comments to output. */, 15 | "resolveJsonModule": true /* Allows importing modules with a ‘.json’ extension */, 16 | /* Strict Type-Checking Options */ 17 | "strict": true /* Enable all strict type-checking options. */, 18 | "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 19 | "strictNullChecks": true /* Enable strict null checks. */, 20 | "strictFunctionTypes": true /* Enable strict checking of function types. */, 21 | "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, 22 | "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, 23 | "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, 24 | /* Additional Checks */ 25 | "noUnusedLocals": true /* Report errors on unused locals. */, 26 | "noUnusedParameters": true /* Report errors on unused parameters. */, 27 | "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, 28 | "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, 29 | 30 | /* Module Resolution Options */ 31 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 32 | 33 | /* Experimental Options */ 34 | "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, 35 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 36 | 37 | /* Advanced Options */ 38 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 39 | }, 40 | "exclude": ["cdk.out", "node_modules"] 41 | } 42 | -------------------------------------------------------------------------------- /source/run-unit-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This assumes all of the OS-level configuration has been completed and git repo has already been cloned 4 | # 5 | # This script should be run from the source directory 6 | # cd source 7 | # ./run-unit-tests.sh 8 | # 9 | 10 | ["$DEBUG" == 'true' ] && set -x 11 | set -e 12 | 13 | # Get reference for all important folders 14 | source_dir="$PWD" 15 | resource_dir="$source_dir/resources" 16 | services_dir="$source_dir/services" 17 | 18 | echo "------------------------------------------------------------------------------" 19 | echo "[Pre-Test] build binaries" 20 | echo "------------------------------------------------------------------------------" 21 | cd $services_dir/transformer 22 | npm run build:all 23 | 24 | cd $services_dir/helper 25 | npm run build:all 26 | 27 | echo "------------------------------------------------------------------------------" 28 | echo "[Test] Resources" 29 | echo "------------------------------------------------------------------------------" 30 | cd $resource_dir 31 | npm run test -- -u 32 | 33 | echo "------------------------------------------------------------------------------" 34 | echo "[Test] helper" 35 | echo "------------------------------------------------------------------------------" 36 | cd $services_dir/helper 37 | npm run test 38 | 39 | echo "------------------------------------------------------------------------------" 40 | echo "[Test] transformer" 41 | echo "------------------------------------------------------------------------------" 42 | cd $services_dir/transformer 43 | npm run test 44 | 45 | -------------------------------------------------------------------------------- /source/services/@aws-solutions/utils/logger.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | /** 4 | * { 5 | emerg: 0, 6 | alert: 1, 7 | crit: 2, 8 | error: 3, 9 | warning: 4, 10 | notice: 5, 11 | info: 6, 12 | debug: 7 13 | } 14 | */ 15 | import { createLogger, transports, format } from "winston"; 16 | const { combine, timestamp, printf } = format; 17 | 18 | /* 19 | * Formatting the output as desired 20 | */ 21 | const myFormat = printf(({ level, label, message }) => { 22 | const _level = level.toUpperCase(); 23 | if (label) return `[${_level}] [${label}] ${message}`; 24 | else return `[${_level}] ${message}`; 25 | }); 26 | 27 | export const logger = createLogger({ 28 | format: combine( 29 | // 30 | // Order is important here, the formats are called in the 31 | // order they are passed to combine. 32 | // 33 | timestamp(), 34 | myFormat 35 | ), 36 | 37 | transports: [ 38 | //cw logs transport channel 39 | new transports.Console({ 40 | level: process.env.LOG_LEVEL, 41 | handleExceptions: true, //handle uncaught exceptions 42 | //format: format.splat() 43 | }), 44 | ], 45 | }); 46 | -------------------------------------------------------------------------------- /source/services/@aws-solutions/utils/metric.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | import got from "got"; 4 | import { logger } from "./logger"; 5 | 6 | const metricsEndpoint = process.env.METRICS_ENDPOINT; 7 | const awsRegion = process.env.AWS_REGION; 8 | const solutionId = process.env.SOLUTION_ID; 9 | const solutionVersion = process.env.SOLUTION_VERSION; 10 | 11 | export const sendDeploymentMetrics = async ( 12 | properties: { [p: string]: string }, 13 | requestType: string 14 | ): Promise<{ [key: string]: unknown }> => { 15 | logger.debug({ 16 | label: "sendDeploymentMetrics", 17 | message: `Sending deployment metrics`, 18 | }); 19 | 20 | const stack = process.env.STACK; 21 | const clusterSize = process.env.CLUSTER_SIZE; 22 | 23 | if (!stack || !clusterSize) 24 | throw new Error("Missing mandatory environment variable"); 25 | 26 | const eventType = `Solution${requestType}`; 27 | const data = { 28 | Event: eventType, 29 | ClusterSize: clusterSize, 30 | Stack: stack, 31 | }; 32 | 33 | // SolutionUuid cannot be passed as environment variable in this case, 34 | // because it is generated after deployment of the Lambda Function 35 | const uuid = properties.SolutionUuid; 36 | const metric = await sendToAwsSolutionsEngineeringTeam(uuid, data); 37 | 38 | return { 39 | Data: metric, 40 | }; 41 | }; 42 | 43 | export async function sendUsageMetrics(totalItemSize: number) { 44 | logger.info({ 45 | label: "sendUsageMetrics", 46 | message: `Sending metrics for indexed data. totalItemSize: ${totalItemSize}`, 47 | }); 48 | const data = { 49 | TotalItemSize: `${totalItemSize}`, 50 | }; 51 | 52 | const uuid = process.env.UUID; 53 | 54 | await sendToAwsSolutionsEngineeringTeam(uuid, data); 55 | } 56 | 57 | async function sendToAwsSolutionsEngineeringTeam( 58 | uuid: string, 59 | data: { [p: string]: string } 60 | ) { 61 | const metric = { 62 | Solution: solutionId, 63 | UUID: uuid, 64 | TimeStamp: new Date().toISOString().replace("T", " ").replace("Z", ""), // Date and time instant in a java.sql.Timestamp compatible format, 65 | Data: { 66 | ...data, 67 | Version: solutionVersion, 68 | Region: awsRegion, 69 | }, 70 | }; 71 | try { 72 | await got(metricsEndpoint, { 73 | method: "POST", 74 | headers: { 75 | "Content-Type": "application/json", 76 | "Content-Length": "" + JSON.stringify(metric).length, 77 | }, 78 | body: JSON.stringify(metric), 79 | }); 80 | logger.debug(`Metric sent: ${JSON.stringify(metric)}`); 81 | } catch (error) { 82 | logger.error( 83 | `error occurred while sending metric: ${(error as Error).message}` 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /source/services/@aws-solutions/utils/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "util", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "util", 9 | "version": "1.0.0", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "got": "11.8.5", 13 | "winston": "^3.8.1" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.3.1", 17 | "ts-node": "^10.8.2", 18 | "typescript": "^5.1.3" 19 | } 20 | }, 21 | "node_modules/@colors/colors": { 22 | "version": "1.6.0", 23 | "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", 24 | "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", 25 | "engines": { 26 | "node": ">=0.1.90" 27 | } 28 | }, 29 | "node_modules/@cspotcode/source-map-support": { 30 | "version": "0.8.1", 31 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 32 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 33 | "dev": true, 34 | "dependencies": { 35 | "@jridgewell/trace-mapping": "0.3.9" 36 | }, 37 | "engines": { 38 | "node": ">=12" 39 | } 40 | }, 41 | "node_modules/@dabh/diagnostics": { 42 | "version": "2.0.3", 43 | "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", 44 | "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", 45 | "dependencies": { 46 | "colorspace": "1.1.x", 47 | "enabled": "2.0.x", 48 | "kuler": "^2.0.0" 49 | } 50 | }, 51 | "node_modules/@jridgewell/resolve-uri": { 52 | "version": "3.1.1", 53 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 54 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 55 | "dev": true, 56 | "engines": { 57 | "node": ">=6.0.0" 58 | } 59 | }, 60 | "node_modules/@jridgewell/sourcemap-codec": { 61 | "version": "1.4.15", 62 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 63 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 64 | "dev": true 65 | }, 66 | "node_modules/@jridgewell/trace-mapping": { 67 | "version": "0.3.9", 68 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 69 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 70 | "dev": true, 71 | "dependencies": { 72 | "@jridgewell/resolve-uri": "^3.0.3", 73 | "@jridgewell/sourcemap-codec": "^1.4.10" 74 | } 75 | }, 76 | "node_modules/@sindresorhus/is": { 77 | "version": "4.6.0", 78 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", 79 | "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", 80 | "engines": { 81 | "node": ">=10" 82 | }, 83 | "funding": { 84 | "url": "https://github.com/sindresorhus/is?sponsor=1" 85 | } 86 | }, 87 | "node_modules/@szmarczak/http-timer": { 88 | "version": "4.0.6", 89 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", 90 | "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", 91 | "dependencies": { 92 | "defer-to-connect": "^2.0.0" 93 | }, 94 | "engines": { 95 | "node": ">=10" 96 | } 97 | }, 98 | "node_modules/@tsconfig/node10": { 99 | "version": "1.0.9", 100 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 101 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 102 | "dev": true 103 | }, 104 | "node_modules/@tsconfig/node12": { 105 | "version": "1.0.11", 106 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 107 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 108 | "dev": true 109 | }, 110 | "node_modules/@tsconfig/node14": { 111 | "version": "1.0.3", 112 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 113 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 114 | "dev": true 115 | }, 116 | "node_modules/@tsconfig/node16": { 117 | "version": "1.0.4", 118 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 119 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 120 | "dev": true 121 | }, 122 | "node_modules/@types/cacheable-request": { 123 | "version": "6.0.3", 124 | "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", 125 | "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", 126 | "dependencies": { 127 | "@types/http-cache-semantics": "*", 128 | "@types/keyv": "^3.1.4", 129 | "@types/node": "*", 130 | "@types/responselike": "^1.0.0" 131 | } 132 | }, 133 | "node_modules/@types/http-cache-semantics": { 134 | "version": "4.0.3", 135 | "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", 136 | "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==" 137 | }, 138 | "node_modules/@types/keyv": { 139 | "version": "3.1.4", 140 | "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", 141 | "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", 142 | "dependencies": { 143 | "@types/node": "*" 144 | } 145 | }, 146 | "node_modules/@types/node": { 147 | "version": "20.8.7", 148 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", 149 | "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", 150 | "dependencies": { 151 | "undici-types": "~5.25.1" 152 | } 153 | }, 154 | "node_modules/@types/responselike": { 155 | "version": "1.0.2", 156 | "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.2.tgz", 157 | "integrity": "sha512-/4YQT5Kp6HxUDb4yhRkm0bJ7TbjvTddqX7PZ5hz6qV3pxSo72f/6YPRo+Mu2DU307tm9IioO69l7uAwn5XNcFA==", 158 | "dependencies": { 159 | "@types/node": "*" 160 | } 161 | }, 162 | "node_modules/@types/triple-beam": { 163 | "version": "1.3.4", 164 | "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.4.tgz", 165 | "integrity": "sha512-HlJjF3wxV4R2VQkFpKe0YqJLilYNgtRtsqqZtby7RkVsSs+i+vbyzjtUwpFEdUCKcrGzCiEJE7F/0mKjh0sunA==" 166 | }, 167 | "node_modules/acorn": { 168 | "version": "8.10.0", 169 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 170 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 171 | "dev": true, 172 | "bin": { 173 | "acorn": "bin/acorn" 174 | }, 175 | "engines": { 176 | "node": ">=0.4.0" 177 | } 178 | }, 179 | "node_modules/acorn-walk": { 180 | "version": "8.2.0", 181 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 182 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 183 | "dev": true, 184 | "engines": { 185 | "node": ">=0.4.0" 186 | } 187 | }, 188 | "node_modules/arg": { 189 | "version": "4.1.3", 190 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 191 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 192 | "dev": true 193 | }, 194 | "node_modules/async": { 195 | "version": "3.2.4", 196 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", 197 | "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" 198 | }, 199 | "node_modules/cacheable-lookup": { 200 | "version": "5.0.4", 201 | "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", 202 | "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", 203 | "engines": { 204 | "node": ">=10.6.0" 205 | } 206 | }, 207 | "node_modules/cacheable-request": { 208 | "version": "7.0.4", 209 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", 210 | "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", 211 | "dependencies": { 212 | "clone-response": "^1.0.2", 213 | "get-stream": "^5.1.0", 214 | "http-cache-semantics": "^4.0.0", 215 | "keyv": "^4.0.0", 216 | "lowercase-keys": "^2.0.0", 217 | "normalize-url": "^6.0.1", 218 | "responselike": "^2.0.0" 219 | }, 220 | "engines": { 221 | "node": ">=8" 222 | } 223 | }, 224 | "node_modules/clone-response": { 225 | "version": "1.0.3", 226 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", 227 | "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", 228 | "dependencies": { 229 | "mimic-response": "^1.0.0" 230 | }, 231 | "funding": { 232 | "url": "https://github.com/sponsors/sindresorhus" 233 | } 234 | }, 235 | "node_modules/color": { 236 | "version": "3.2.1", 237 | "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", 238 | "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", 239 | "dependencies": { 240 | "color-convert": "^1.9.3", 241 | "color-string": "^1.6.0" 242 | } 243 | }, 244 | "node_modules/color-convert": { 245 | "version": "1.9.3", 246 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 247 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 248 | "dependencies": { 249 | "color-name": "1.1.3" 250 | } 251 | }, 252 | "node_modules/color-name": { 253 | "version": "1.1.3", 254 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 255 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 256 | }, 257 | "node_modules/color-string": { 258 | "version": "1.9.1", 259 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", 260 | "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", 261 | "dependencies": { 262 | "color-name": "^1.0.0", 263 | "simple-swizzle": "^0.2.2" 264 | } 265 | }, 266 | "node_modules/colorspace": { 267 | "version": "1.1.4", 268 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", 269 | "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", 270 | "dependencies": { 271 | "color": "^3.1.3", 272 | "text-hex": "1.0.x" 273 | } 274 | }, 275 | "node_modules/create-require": { 276 | "version": "1.1.1", 277 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 278 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 279 | "dev": true 280 | }, 281 | "node_modules/decompress-response": { 282 | "version": "6.0.0", 283 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 284 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 285 | "dependencies": { 286 | "mimic-response": "^3.1.0" 287 | }, 288 | "engines": { 289 | "node": ">=10" 290 | }, 291 | "funding": { 292 | "url": "https://github.com/sponsors/sindresorhus" 293 | } 294 | }, 295 | "node_modules/decompress-response/node_modules/mimic-response": { 296 | "version": "3.1.0", 297 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 298 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", 299 | "engines": { 300 | "node": ">=10" 301 | }, 302 | "funding": { 303 | "url": "https://github.com/sponsors/sindresorhus" 304 | } 305 | }, 306 | "node_modules/defer-to-connect": { 307 | "version": "2.0.1", 308 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", 309 | "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", 310 | "engines": { 311 | "node": ">=10" 312 | } 313 | }, 314 | "node_modules/diff": { 315 | "version": "4.0.2", 316 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 317 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 318 | "dev": true, 319 | "engines": { 320 | "node": ">=0.3.1" 321 | } 322 | }, 323 | "node_modules/enabled": { 324 | "version": "2.0.0", 325 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", 326 | "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" 327 | }, 328 | "node_modules/end-of-stream": { 329 | "version": "1.4.4", 330 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 331 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 332 | "dependencies": { 333 | "once": "^1.4.0" 334 | } 335 | }, 336 | "node_modules/fecha": { 337 | "version": "4.2.3", 338 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", 339 | "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" 340 | }, 341 | "node_modules/fn.name": { 342 | "version": "1.1.0", 343 | "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", 344 | "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" 345 | }, 346 | "node_modules/get-stream": { 347 | "version": "5.2.0", 348 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 349 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 350 | "dependencies": { 351 | "pump": "^3.0.0" 352 | }, 353 | "engines": { 354 | "node": ">=8" 355 | }, 356 | "funding": { 357 | "url": "https://github.com/sponsors/sindresorhus" 358 | } 359 | }, 360 | "node_modules/got": { 361 | "version": "11.8.5", 362 | "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", 363 | "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", 364 | "dependencies": { 365 | "@sindresorhus/is": "^4.0.0", 366 | "@szmarczak/http-timer": "^4.0.5", 367 | "@types/cacheable-request": "^6.0.1", 368 | "@types/responselike": "^1.0.0", 369 | "cacheable-lookup": "^5.0.3", 370 | "cacheable-request": "^7.0.2", 371 | "decompress-response": "^6.0.0", 372 | "http2-wrapper": "^1.0.0-beta.5.2", 373 | "lowercase-keys": "^2.0.0", 374 | "p-cancelable": "^2.0.0", 375 | "responselike": "^2.0.0" 376 | }, 377 | "engines": { 378 | "node": ">=10.19.0" 379 | }, 380 | "funding": { 381 | "url": "https://github.com/sindresorhus/got?sponsor=1" 382 | } 383 | }, 384 | "node_modules/http-cache-semantics": { 385 | "version": "4.1.1", 386 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", 387 | "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" 388 | }, 389 | "node_modules/http2-wrapper": { 390 | "version": "1.0.3", 391 | "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", 392 | "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", 393 | "dependencies": { 394 | "quick-lru": "^5.1.1", 395 | "resolve-alpn": "^1.0.0" 396 | }, 397 | "engines": { 398 | "node": ">=10.19.0" 399 | } 400 | }, 401 | "node_modules/inherits": { 402 | "version": "2.0.4", 403 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 404 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 405 | }, 406 | "node_modules/is-arrayish": { 407 | "version": "0.3.2", 408 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 409 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 410 | }, 411 | "node_modules/is-stream": { 412 | "version": "2.0.1", 413 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", 414 | "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", 415 | "engines": { 416 | "node": ">=8" 417 | }, 418 | "funding": { 419 | "url": "https://github.com/sponsors/sindresorhus" 420 | } 421 | }, 422 | "node_modules/json-buffer": { 423 | "version": "3.0.1", 424 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 425 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" 426 | }, 427 | "node_modules/keyv": { 428 | "version": "4.5.4", 429 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 430 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 431 | "dependencies": { 432 | "json-buffer": "3.0.1" 433 | } 434 | }, 435 | "node_modules/kuler": { 436 | "version": "2.0.0", 437 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", 438 | "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" 439 | }, 440 | "node_modules/logform": { 441 | "version": "2.6.0", 442 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", 443 | "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", 444 | "dependencies": { 445 | "@colors/colors": "1.6.0", 446 | "@types/triple-beam": "^1.3.2", 447 | "fecha": "^4.2.0", 448 | "ms": "^2.1.1", 449 | "safe-stable-stringify": "^2.3.1", 450 | "triple-beam": "^1.3.0" 451 | }, 452 | "engines": { 453 | "node": ">= 12.0.0" 454 | } 455 | }, 456 | "node_modules/lowercase-keys": { 457 | "version": "2.0.0", 458 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 459 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", 460 | "engines": { 461 | "node": ">=8" 462 | } 463 | }, 464 | "node_modules/make-error": { 465 | "version": "1.3.6", 466 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 467 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 468 | "dev": true 469 | }, 470 | "node_modules/mimic-response": { 471 | "version": "1.0.1", 472 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 473 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", 474 | "engines": { 475 | "node": ">=4" 476 | } 477 | }, 478 | "node_modules/ms": { 479 | "version": "2.1.3", 480 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 481 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 482 | }, 483 | "node_modules/normalize-url": { 484 | "version": "6.1.0", 485 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", 486 | "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", 487 | "engines": { 488 | "node": ">=10" 489 | }, 490 | "funding": { 491 | "url": "https://github.com/sponsors/sindresorhus" 492 | } 493 | }, 494 | "node_modules/once": { 495 | "version": "1.4.0", 496 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 497 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 498 | "dependencies": { 499 | "wrappy": "1" 500 | } 501 | }, 502 | "node_modules/one-time": { 503 | "version": "1.0.0", 504 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", 505 | "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", 506 | "dependencies": { 507 | "fn.name": "1.x.x" 508 | } 509 | }, 510 | "node_modules/p-cancelable": { 511 | "version": "2.1.1", 512 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", 513 | "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", 514 | "engines": { 515 | "node": ">=8" 516 | } 517 | }, 518 | "node_modules/pump": { 519 | "version": "3.0.0", 520 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 521 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 522 | "dependencies": { 523 | "end-of-stream": "^1.1.0", 524 | "once": "^1.3.1" 525 | } 526 | }, 527 | "node_modules/quick-lru": { 528 | "version": "5.1.1", 529 | "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", 530 | "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", 531 | "engines": { 532 | "node": ">=10" 533 | }, 534 | "funding": { 535 | "url": "https://github.com/sponsors/sindresorhus" 536 | } 537 | }, 538 | "node_modules/readable-stream": { 539 | "version": "3.6.2", 540 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 541 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 542 | "dependencies": { 543 | "inherits": "^2.0.3", 544 | "string_decoder": "^1.1.1", 545 | "util-deprecate": "^1.0.1" 546 | }, 547 | "engines": { 548 | "node": ">= 6" 549 | } 550 | }, 551 | "node_modules/resolve-alpn": { 552 | "version": "1.2.1", 553 | "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", 554 | "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" 555 | }, 556 | "node_modules/responselike": { 557 | "version": "2.0.1", 558 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", 559 | "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", 560 | "dependencies": { 561 | "lowercase-keys": "^2.0.0" 562 | }, 563 | "funding": { 564 | "url": "https://github.com/sponsors/sindresorhus" 565 | } 566 | }, 567 | "node_modules/safe-buffer": { 568 | "version": "5.2.1", 569 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 570 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 571 | "funding": [ 572 | { 573 | "type": "github", 574 | "url": "https://github.com/sponsors/feross" 575 | }, 576 | { 577 | "type": "patreon", 578 | "url": "https://www.patreon.com/feross" 579 | }, 580 | { 581 | "type": "consulting", 582 | "url": "https://feross.org/support" 583 | } 584 | ] 585 | }, 586 | "node_modules/safe-stable-stringify": { 587 | "version": "2.4.3", 588 | "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", 589 | "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", 590 | "engines": { 591 | "node": ">=10" 592 | } 593 | }, 594 | "node_modules/simple-swizzle": { 595 | "version": "0.2.2", 596 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 597 | "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", 598 | "dependencies": { 599 | "is-arrayish": "^0.3.1" 600 | } 601 | }, 602 | "node_modules/stack-trace": { 603 | "version": "0.0.10", 604 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 605 | "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", 606 | "engines": { 607 | "node": "*" 608 | } 609 | }, 610 | "node_modules/string_decoder": { 611 | "version": "1.3.0", 612 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 613 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 614 | "dependencies": { 615 | "safe-buffer": "~5.2.0" 616 | } 617 | }, 618 | "node_modules/text-hex": { 619 | "version": "1.0.0", 620 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 621 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" 622 | }, 623 | "node_modules/triple-beam": { 624 | "version": "1.4.1", 625 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", 626 | "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", 627 | "engines": { 628 | "node": ">= 14.0.0" 629 | } 630 | }, 631 | "node_modules/ts-node": { 632 | "version": "10.9.1", 633 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 634 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 635 | "dev": true, 636 | "dependencies": { 637 | "@cspotcode/source-map-support": "^0.8.0", 638 | "@tsconfig/node10": "^1.0.7", 639 | "@tsconfig/node12": "^1.0.7", 640 | "@tsconfig/node14": "^1.0.0", 641 | "@tsconfig/node16": "^1.0.2", 642 | "acorn": "^8.4.1", 643 | "acorn-walk": "^8.1.1", 644 | "arg": "^4.1.0", 645 | "create-require": "^1.1.0", 646 | "diff": "^4.0.1", 647 | "make-error": "^1.1.1", 648 | "v8-compile-cache-lib": "^3.0.1", 649 | "yn": "3.1.1" 650 | }, 651 | "bin": { 652 | "ts-node": "dist/bin.js", 653 | "ts-node-cwd": "dist/bin-cwd.js", 654 | "ts-node-esm": "dist/bin-esm.js", 655 | "ts-node-script": "dist/bin-script.js", 656 | "ts-node-transpile-only": "dist/bin-transpile.js", 657 | "ts-script": "dist/bin-script-deprecated.js" 658 | }, 659 | "peerDependencies": { 660 | "@swc/core": ">=1.2.50", 661 | "@swc/wasm": ">=1.2.50", 662 | "@types/node": "*", 663 | "typescript": ">=2.7" 664 | }, 665 | "peerDependenciesMeta": { 666 | "@swc/core": { 667 | "optional": true 668 | }, 669 | "@swc/wasm": { 670 | "optional": true 671 | } 672 | } 673 | }, 674 | "node_modules/typescript": { 675 | "version": "5.2.2", 676 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 677 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 678 | "dev": true, 679 | "bin": { 680 | "tsc": "bin/tsc", 681 | "tsserver": "bin/tsserver" 682 | }, 683 | "engines": { 684 | "node": ">=14.17" 685 | } 686 | }, 687 | "node_modules/undici-types": { 688 | "version": "5.25.3", 689 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", 690 | "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==" 691 | }, 692 | "node_modules/util-deprecate": { 693 | "version": "1.0.2", 694 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 695 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 696 | }, 697 | "node_modules/v8-compile-cache-lib": { 698 | "version": "3.0.1", 699 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 700 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 701 | "dev": true 702 | }, 703 | "node_modules/winston": { 704 | "version": "3.11.0", 705 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", 706 | "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", 707 | "dependencies": { 708 | "@colors/colors": "^1.6.0", 709 | "@dabh/diagnostics": "^2.0.2", 710 | "async": "^3.2.3", 711 | "is-stream": "^2.0.0", 712 | "logform": "^2.4.0", 713 | "one-time": "^1.0.0", 714 | "readable-stream": "^3.4.0", 715 | "safe-stable-stringify": "^2.3.1", 716 | "stack-trace": "0.0.x", 717 | "triple-beam": "^1.3.0", 718 | "winston-transport": "^4.5.0" 719 | }, 720 | "engines": { 721 | "node": ">= 12.0.0" 722 | } 723 | }, 724 | "node_modules/winston-transport": { 725 | "version": "4.6.0", 726 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", 727 | "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", 728 | "dependencies": { 729 | "logform": "^2.3.2", 730 | "readable-stream": "^3.6.0", 731 | "triple-beam": "^1.3.0" 732 | }, 733 | "engines": { 734 | "node": ">= 12.0.0" 735 | } 736 | }, 737 | "node_modules/wrappy": { 738 | "version": "1.0.2", 739 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 740 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 741 | }, 742 | "node_modules/yn": { 743 | "version": "3.1.1", 744 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 745 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 746 | "dev": true, 747 | "engines": { 748 | "node": ">=6" 749 | } 750 | } 751 | } 752 | } 753 | -------------------------------------------------------------------------------- /source/services/@aws-solutions/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "util", 3 | "version": "1.0.0", 4 | "description": "utility for aws-solutions", 5 | "license": "Apache-2.0", 6 | "scripts": { 7 | "build:ts": "npx tsc --project ./tsconfig.json" 8 | }, 9 | "dependencies": { 10 | "got": "11.8.5", 11 | "winston": "^3.8.1" 12 | }, 13 | "devDependencies": { 14 | "ts-node": "^10.8.2", 15 | "typescript": "^5.1.3", 16 | "@types/node": "^20.3.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /source/services/@aws-solutions/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /source/services/helper/PromiseConstructor.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | export interface PromiseResolution { 4 | status: "fulfilled"; 5 | value: T; 6 | } 7 | 8 | export interface PromiseRejection { 9 | status: "rejected"; 10 | reason: E; 11 | } 12 | 13 | export type PromiseResult = 14 | | PromiseResolution 15 | | PromiseRejection; 16 | 17 | export type PromiseList = { 18 | [P in keyof T]: Promise; 19 | }; 20 | 21 | export type PromiseResultList = { 22 | [P in keyof T]: PromiseResult; 23 | }; 24 | 25 | declare global { 26 | interface PromiseConstructor { 27 | allSettled(): Promise<[]>; 28 | allSettled( 29 | list: PromiseList 30 | ): Promise>; 31 | allSettled(iterable: Iterable): Promise>>; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /source/services/helper/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | import { v4 as uuidv4 } from "uuid"; 4 | import { logger } from "logger"; 5 | import { CloudWatchLogs, EC2, IAM } from "aws-sdk"; 6 | import { 7 | Context, 8 | CloudFormationCustomResourceEvent, 9 | CloudFormationCustomResourceUpdateEvent, 10 | } from "aws-lambda"; 11 | import { sendDeploymentMetrics } from "metric"; 12 | 13 | const awsClients = { 14 | ec2: "2016-11-15", 15 | cwLogs: "2014-03-28", 16 | iam: "2010-05-08", 17 | }; 18 | 19 | interface IResponse { 20 | responseData: { [key: string]: unknown }; 21 | status: string; 22 | } 23 | 24 | export const handler = async ( 25 | event: CloudFormationCustomResourceEvent, 26 | context: Context 27 | ) => { 28 | logger.debug({ 29 | label: "helper", 30 | message: `received event: ${JSON.stringify(event)}`, 31 | }); 32 | 33 | const properties = event.ResourceProperties; 34 | 35 | /** 36 | * handle UUID 37 | */ 38 | if ( 39 | event.ResourceType === "Custom::CreateUUID" && 40 | event.RequestType === "Create" 41 | ) { 42 | const { responseData, status } = createUUID(); 43 | return responseBody(event, context.logStreamName, status, responseData); 44 | } 45 | 46 | /** 47 | * handle ES Service role 48 | */ 49 | if ( 50 | event.ResourceType === "Custom::CreateESServiceRole" && 51 | event.RequestType === "Create" 52 | ) { 53 | const { responseData, status } = await createESRole(); 54 | return responseBody(event, context.logStreamName, status, responseData); 55 | } 56 | 57 | /** 58 | * handle launch data 59 | */ 60 | if ( 61 | event.ResourceType === "Custom::LaunchData" && 62 | process.env.SEND_METRIC === "Yes" 63 | ) { 64 | const responseData = await sendDeploymentMetrics( 65 | properties, 66 | event.RequestType 67 | ); 68 | return responseBody(event, context.logStreamName, "SUCCESS", responseData); 69 | } 70 | 71 | /** 72 | * handle CW destinations 73 | */ 74 | if (event.ResourceType === "Custom::CWDestination") { 75 | const { responseData, status } = await crudDestinations( 76 | properties, 77 | event.RequestType 78 | ); 79 | return responseBody(event, context.logStreamName, status, responseData); 80 | } 81 | 82 | /** 83 | * default 84 | */ 85 | // send response to custom resource 86 | return responseBody(event, context.logStreamName, "SUCCESS", { 87 | Data: "no data", 88 | }); 89 | }; 90 | 91 | /** 92 | * @description create UUID for customer deployment 93 | * @returns 94 | */ 95 | const createUUID = (): IResponse => { 96 | const responseData = { UUID: uuidv4() }; 97 | const status = "SUCCESS"; 98 | logger.info({ 99 | label: "helper/createUUID", 100 | message: `uuid create: ${responseData.UUID}`, 101 | }); 102 | return { responseData, status }; 103 | }; 104 | 105 | /** 106 | * @description create ES service linked role 107 | * @returns 108 | */ 109 | 110 | const createESRole = async (): Promise => { 111 | const iam = new IAM({ 112 | apiVersion: awsClients.iam, 113 | customUserAgent: process.env.CUSTOM_SDK_USER_AGENT, 114 | }); 115 | 116 | let responseData: { 117 | [key: string]: string; 118 | } = { Data: "no data" }; 119 | let status = "SUCCESS"; 120 | 121 | await iam 122 | .createServiceLinkedRole({ AWSServiceName: "es.amazonaws.com" }) 123 | .promise() 124 | .catch((e) => { 125 | logger.error({ 126 | label: "helper/createESRole", 127 | message: e, 128 | }); 129 | if ((e as Error).name !== "InvalidInput") { 130 | // InvalidInput ES service linked role already exists 131 | responseData = { 132 | Error: 133 | "failed to create ES service linked role, please see in cw logs for more details", 134 | }; 135 | status = "FAILED"; 136 | } 137 | return { responseData, status }; 138 | }); 139 | logger.info({ 140 | label: "helper/createESRole", 141 | message: `es service linked role created`, 142 | }); 143 | return { responseData, status }; 144 | }; 145 | 146 | /** 147 | * @description crud for cw destinations 148 | * @returns 149 | */ 150 | const crudDestinations = async ( 151 | properties: any, 152 | requestType: string 153 | ): Promise => { 154 | let responseData: { 155 | [key: string]: string; 156 | } = { Data: "no data" }; 157 | let status = "SUCCESS"; 158 | try { 159 | const allRegions = await getRegions(); 160 | 161 | // delete destinations 162 | if (requestType === "Delete") 163 | await deleteDestination(properties.DestinationName, allRegions); 164 | // create/update destinations 165 | else { 166 | let spokeRegions = properties.Regions; 167 | logger.debug({ 168 | label: "helper/CWDestination", 169 | message: `Regions to ${requestType} CloudWatch destinations: ${spokeRegions}`, 170 | }); 171 | if (spokeRegions[0] === "All") { 172 | spokeRegions = allRegions; 173 | } 174 | await putDestination( 175 | spokeRegions, 176 | allRegions, 177 | properties.DestinationName, 178 | properties.Role, 179 | properties.DataStream, 180 | properties.SpokeAccounts 181 | ); 182 | } 183 | } catch (e) { 184 | logger.error({ 185 | label: "helper/CWDestination", 186 | message: e, 187 | }); 188 | responseData = { 189 | Error: `failed to ${requestType} CW destinations, please see in cw logs for more details`, 190 | }; 191 | status = "FAILED"; 192 | } 193 | return { responseData, status }; 194 | }; 195 | 196 | /** 197 | * @description get list of ec2 regions 198 | */ 199 | async function getRegions(): Promise { 200 | logger.info({ 201 | label: "helper/getRegions", 202 | message: `getting ec2 regions`, 203 | }); 204 | try { 205 | const ec2 = new EC2({ 206 | apiVersion: awsClients.ec2, 207 | customUserAgent: process.env.CUSTOM_SDK_USER_AGENT, 208 | }); 209 | const _r = await ec2.describeRegions().promise(); 210 | if (!_r.Regions) throw new Error("failed to describe regions"); 211 | 212 | const regions = _r.Regions.map((region) => { 213 | return region.RegionName; 214 | }); 215 | logger.debug({ 216 | label: "helper/getRegions", 217 | message: `${JSON.stringify({ regions: regions })}`, 218 | }); 219 | return regions; 220 | } catch (e) { 221 | logger.error({ 222 | label: "helper/getRegions", 223 | message: e, 224 | }); 225 | throw new Error("error in getting regions"); 226 | } 227 | } 228 | 229 | /** 230 | * @description create cw destinations 231 | * @param {string[]} regions - regions for spokes 232 | * @param {string} destinationName - cw logs destination name 233 | * @param {string} roleArn - ARN of IAM role that grants CloudWatch Logs permissions to call the Amazon Kinesis PutRecord operation on the destination stream 234 | * @param {string} kinesisStreamArn - The ARN of an Amazon Kinesis stream to which to deliver matching log events 235 | * @param {string[]} spokeAccnts - list of spoke account ids 236 | */ 237 | async function putDestination( 238 | regions: string[], 239 | awsRegions: string[], 240 | destinationName: string, 241 | roleArn: string, 242 | kinesisStreamArn: string, 243 | spokeAccnts: string[] 244 | ) { 245 | logger.info({ 246 | label: "helper/putDestination", 247 | message: `putting cw logs destinations for spokes`, 248 | }); 249 | try { 250 | // check if provided region list is valid 251 | const regionValid = await areRegionsValid(regions, awsRegions); 252 | if (regionValid) { 253 | await deleteDestination(destinationName, regions); 254 | await Promise.all( 255 | regions.map(async (region) => { 256 | logger.debug({ 257 | label: "helper/putDestination", 258 | message: `creating cw logs destination in ${region}`, 259 | }); 260 | 261 | const cwLogs = new CloudWatchLogs({ 262 | apiVersion: awsClients.cwLogs, 263 | region: region, 264 | customUserAgent: process.env.CUSTOM_SDK_USER_AGENT, 265 | }); 266 | 267 | //put destination 268 | const dest: CloudWatchLogs.PutDestinationResponse = await cwLogs 269 | .putDestination({ 270 | destinationName: destinationName, 271 | roleArn: roleArn, 272 | targetArn: kinesisStreamArn, 273 | }) 274 | .promise(); 275 | 276 | // put access policy 277 | const accessPolicy = { 278 | Version: "2012-10-17", 279 | Statement: [ 280 | { 281 | Sid: "AllowSpokesSubscribe", 282 | Effect: "Allow", 283 | Principal: { 284 | AWS: spokeAccnts, 285 | }, 286 | Action: "logs:PutSubscriptionFilter", 287 | Resource: dest.destination?.arn, 288 | }, 289 | ], 290 | }; 291 | await cwLogs 292 | .putDestinationPolicy({ 293 | destinationName: destinationName, 294 | accessPolicy: JSON.stringify(accessPolicy), // for spoke accounts as principals 295 | }) 296 | .promise(); 297 | logger.debug({ 298 | label: "helper/putDestinations", 299 | message: `cw logs destination created in ${region}`, 300 | }); 301 | }) 302 | ); 303 | logger.info({ 304 | label: "helper/putDestinations", 305 | message: `All cw logs destinations created`, 306 | }); 307 | } else { 308 | throw new Error("invalid regions"); 309 | } 310 | } catch (e) { 311 | logger.error({ 312 | label: "helper/putDestination", 313 | message: e, 314 | }); 315 | throw new Error("error in creating cw log destination"); 316 | } 317 | } 318 | 319 | /** 320 | * @description delete cw destinations 321 | * @param {string} destinationName - cw logs destination name 322 | */ 323 | async function deleteDestination(destinationName: string, regions: string[]) { 324 | logger.info({ 325 | label: "helper/deleteDestination", 326 | message: `deleting cw logs destinations `, 327 | }); 328 | await Promise.allSettled( 329 | regions.map(async (region) => { 330 | const cwLogs = new CloudWatchLogs({ 331 | apiVersion: awsClients.cwLogs, 332 | region: region, 333 | customUserAgent: process.env.CUSTOM_SDK_USER_AGENT, 334 | }); 335 | await cwLogs 336 | .deleteDestination({ destinationName: destinationName }) 337 | .promise() 338 | .then(() => { 339 | logger.debug({ 340 | label: "helper/deleteDestination", 341 | message: `cw logs destination deleted in ${region}`, 342 | }); 343 | }) 344 | .catch((e) => { 345 | logger.warn({ 346 | label: `helper/deleteDestination`, 347 | message: `${region}: ${(e as Error).message}`, 348 | }); 349 | }); 350 | }) 351 | ); 352 | logger.info({ 353 | label: "helper/deleteDestinations", 354 | message: `All cw logs destinations deleted`, 355 | }); 356 | } 357 | 358 | /** 359 | * @description check if region list is valid 360 | * @param {string[]} regions - region list for spokes 361 | */ 362 | async function areRegionsValid(regions: string[], awsRegions: string[]) { 363 | logger.debug({ 364 | label: "helper/areRegionsValid", 365 | message: `checking if region parameter is valid`, 366 | }); 367 | 368 | if (!(awsRegions instanceof Array)) throw new Error("no regions found"); 369 | try { 370 | await Promise.all( 371 | regions.map((region) => { 372 | if (!awsRegions.includes(region)) 373 | throw new Error("invalid region provided"); 374 | }) 375 | ); 376 | return true; 377 | } catch (e) { 378 | logger.error({ 379 | label: "helper/areRegionsValid", 380 | message: `${(e as Error).message}`, 381 | }); 382 | return false; 383 | } 384 | } 385 | 386 | const responseBody = async ( 387 | event: CloudFormationCustomResourceEvent, 388 | logStreamName: string, 389 | responseStatus: string, 390 | responseData: any 391 | ) => { 392 | const responseBody = { 393 | Status: responseStatus, 394 | Reason: `${JSON.stringify(responseData)}`, 395 | PhysicalResourceId: 396 | (event as CloudFormationCustomResourceUpdateEvent).PhysicalResourceId || 397 | logStreamName, 398 | StackId: event.StackId, 399 | RequestId: event.RequestId, 400 | LogicalResourceId: event.LogicalResourceId, 401 | Data: responseData, 402 | }; 403 | 404 | logger.debug({ 405 | label: "helper/responseBody", 406 | message: `Response Body: ${JSON.stringify(responseBody)}`, 407 | }); 408 | 409 | if (responseStatus === "FAILED") { 410 | throw new Error(responseBody.Data.Error); 411 | } else return responseBody; 412 | }; 413 | -------------------------------------------------------------------------------- /source/services/helper/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cl-helper", 3 | "version": "4.0.2", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cl-helper", 9 | "version": "4.0.2", 10 | "hasInstallScript": true, 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "aws-sdk": "^2.1354.0", 14 | "uuid": "^9.0.0" 15 | }, 16 | "devDependencies": { 17 | "@types/aws-lambda": "^8.10.114", 18 | "@types/node": "^20.3.1", 19 | "@types/uuid": "^9.0.2", 20 | "typescript": "^5.1.3" 21 | } 22 | }, 23 | "node_modules/@types/aws-lambda": { 24 | "version": "8.10.125", 25 | "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.125.tgz", 26 | "integrity": "sha512-Vqw/WMlV4O1fJT6capim01v7VLDZkcX1n6Yhb52E7IfnMqYbNfwHfyDV8rRN42NLBtdDvfaqcCqs2K0fr5ljZw==", 27 | "dev": true 28 | }, 29 | "node_modules/@types/node": { 30 | "version": "20.8.7", 31 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", 32 | "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", 33 | "dev": true, 34 | "dependencies": { 35 | "undici-types": "~5.25.1" 36 | } 37 | }, 38 | "node_modules/@types/uuid": { 39 | "version": "9.0.6", 40 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", 41 | "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", 42 | "dev": true 43 | }, 44 | "node_modules/available-typed-arrays": { 45 | "version": "1.0.5", 46 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 47 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 48 | "engines": { 49 | "node": ">= 0.4" 50 | }, 51 | "funding": { 52 | "url": "https://github.com/sponsors/ljharb" 53 | } 54 | }, 55 | "node_modules/aws-sdk": { 56 | "version": "2.1477.0", 57 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1477.0.tgz", 58 | "integrity": "sha512-DLsrKosrKRe5P1E+BcJAVpOXkma4oUOrcyBUridDmUhdf9k3jj5dnL1roFuDpTmNDDhK8a1tUgY3wmXoKQtv7A==", 59 | "dependencies": { 60 | "buffer": "4.9.2", 61 | "events": "1.1.1", 62 | "ieee754": "1.1.13", 63 | "jmespath": "0.16.0", 64 | "querystring": "0.2.0", 65 | "sax": "1.2.1", 66 | "url": "0.10.3", 67 | "util": "^0.12.4", 68 | "uuid": "8.0.0", 69 | "xml2js": "0.5.0" 70 | }, 71 | "engines": { 72 | "node": ">= 10.0.0" 73 | } 74 | }, 75 | "node_modules/aws-sdk/node_modules/uuid": { 76 | "version": "8.0.0", 77 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", 78 | "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", 79 | "bin": { 80 | "uuid": "dist/bin/uuid" 81 | } 82 | }, 83 | "node_modules/base64-js": { 84 | "version": "1.5.1", 85 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 86 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 87 | "funding": [ 88 | { 89 | "type": "github", 90 | "url": "https://github.com/sponsors/feross" 91 | }, 92 | { 93 | "type": "patreon", 94 | "url": "https://www.patreon.com/feross" 95 | }, 96 | { 97 | "type": "consulting", 98 | "url": "https://feross.org/support" 99 | } 100 | ] 101 | }, 102 | "node_modules/buffer": { 103 | "version": "4.9.2", 104 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 105 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 106 | "dependencies": { 107 | "base64-js": "^1.0.2", 108 | "ieee754": "^1.1.4", 109 | "isarray": "^1.0.0" 110 | } 111 | }, 112 | "node_modules/call-bind": { 113 | "version": "1.0.4", 114 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.4.tgz", 115 | "integrity": "sha512-e68w37XfAb5fL5M3NTxqKLcXRUkL2/kFlQjQjE/8jvPMBKmO5ZDycRkS/DrZRXjegOzwWzEwW88m+8r+D0PUUA==", 116 | "dependencies": { 117 | "function-bind": "^1.1.2", 118 | "get-intrinsic": "^1.2.1", 119 | "set-function-length": "^1.1.0" 120 | }, 121 | "funding": { 122 | "url": "https://github.com/sponsors/ljharb" 123 | } 124 | }, 125 | "node_modules/define-data-property": { 126 | "version": "1.1.1", 127 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", 128 | "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", 129 | "dependencies": { 130 | "get-intrinsic": "^1.2.1", 131 | "gopd": "^1.0.1", 132 | "has-property-descriptors": "^1.0.0" 133 | }, 134 | "engines": { 135 | "node": ">= 0.4" 136 | } 137 | }, 138 | "node_modules/events": { 139 | "version": "1.1.1", 140 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 141 | "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", 142 | "engines": { 143 | "node": ">=0.4.x" 144 | } 145 | }, 146 | "node_modules/for-each": { 147 | "version": "0.3.3", 148 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 149 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 150 | "dependencies": { 151 | "is-callable": "^1.1.3" 152 | } 153 | }, 154 | "node_modules/function-bind": { 155 | "version": "1.1.2", 156 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 157 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 158 | "funding": { 159 | "url": "https://github.com/sponsors/ljharb" 160 | } 161 | }, 162 | "node_modules/get-intrinsic": { 163 | "version": "1.2.1", 164 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", 165 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", 166 | "dependencies": { 167 | "function-bind": "^1.1.1", 168 | "has": "^1.0.3", 169 | "has-proto": "^1.0.1", 170 | "has-symbols": "^1.0.3" 171 | }, 172 | "funding": { 173 | "url": "https://github.com/sponsors/ljharb" 174 | } 175 | }, 176 | "node_modules/gopd": { 177 | "version": "1.0.1", 178 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 179 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 180 | "dependencies": { 181 | "get-intrinsic": "^1.1.3" 182 | }, 183 | "funding": { 184 | "url": "https://github.com/sponsors/ljharb" 185 | } 186 | }, 187 | "node_modules/has": { 188 | "version": "1.0.4", 189 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", 190 | "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", 191 | "engines": { 192 | "node": ">= 0.4.0" 193 | } 194 | }, 195 | "node_modules/has-property-descriptors": { 196 | "version": "1.0.0", 197 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 198 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 199 | "dependencies": { 200 | "get-intrinsic": "^1.1.1" 201 | }, 202 | "funding": { 203 | "url": "https://github.com/sponsors/ljharb" 204 | } 205 | }, 206 | "node_modules/has-proto": { 207 | "version": "1.0.1", 208 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 209 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 210 | "engines": { 211 | "node": ">= 0.4" 212 | }, 213 | "funding": { 214 | "url": "https://github.com/sponsors/ljharb" 215 | } 216 | }, 217 | "node_modules/has-symbols": { 218 | "version": "1.0.3", 219 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 220 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 221 | "engines": { 222 | "node": ">= 0.4" 223 | }, 224 | "funding": { 225 | "url": "https://github.com/sponsors/ljharb" 226 | } 227 | }, 228 | "node_modules/has-tostringtag": { 229 | "version": "1.0.0", 230 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 231 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 232 | "dependencies": { 233 | "has-symbols": "^1.0.2" 234 | }, 235 | "engines": { 236 | "node": ">= 0.4" 237 | }, 238 | "funding": { 239 | "url": "https://github.com/sponsors/ljharb" 240 | } 241 | }, 242 | "node_modules/ieee754": { 243 | "version": "1.1.13", 244 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 245 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 246 | }, 247 | "node_modules/inherits": { 248 | "version": "2.0.4", 249 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 250 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 251 | }, 252 | "node_modules/is-arguments": { 253 | "version": "1.1.1", 254 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 255 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 256 | "dependencies": { 257 | "call-bind": "^1.0.2", 258 | "has-tostringtag": "^1.0.0" 259 | }, 260 | "engines": { 261 | "node": ">= 0.4" 262 | }, 263 | "funding": { 264 | "url": "https://github.com/sponsors/ljharb" 265 | } 266 | }, 267 | "node_modules/is-callable": { 268 | "version": "1.2.7", 269 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 270 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 271 | "engines": { 272 | "node": ">= 0.4" 273 | }, 274 | "funding": { 275 | "url": "https://github.com/sponsors/ljharb" 276 | } 277 | }, 278 | "node_modules/is-generator-function": { 279 | "version": "1.0.10", 280 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", 281 | "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", 282 | "dependencies": { 283 | "has-tostringtag": "^1.0.0" 284 | }, 285 | "engines": { 286 | "node": ">= 0.4" 287 | }, 288 | "funding": { 289 | "url": "https://github.com/sponsors/ljharb" 290 | } 291 | }, 292 | "node_modules/is-typed-array": { 293 | "version": "1.1.12", 294 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", 295 | "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", 296 | "dependencies": { 297 | "which-typed-array": "^1.1.11" 298 | }, 299 | "engines": { 300 | "node": ">= 0.4" 301 | }, 302 | "funding": { 303 | "url": "https://github.com/sponsors/ljharb" 304 | } 305 | }, 306 | "node_modules/isarray": { 307 | "version": "1.0.0", 308 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 309 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" 310 | }, 311 | "node_modules/jmespath": { 312 | "version": "0.16.0", 313 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", 314 | "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", 315 | "engines": { 316 | "node": ">= 0.6.0" 317 | } 318 | }, 319 | "node_modules/punycode": { 320 | "version": "1.3.2", 321 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 322 | "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" 323 | }, 324 | "node_modules/querystring": { 325 | "version": "0.2.0", 326 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 327 | "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", 328 | "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", 329 | "engines": { 330 | "node": ">=0.4.x" 331 | } 332 | }, 333 | "node_modules/sax": { 334 | "version": "1.2.1", 335 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 336 | "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" 337 | }, 338 | "node_modules/set-function-length": { 339 | "version": "1.1.1", 340 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", 341 | "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", 342 | "dependencies": { 343 | "define-data-property": "^1.1.1", 344 | "get-intrinsic": "^1.2.1", 345 | "gopd": "^1.0.1", 346 | "has-property-descriptors": "^1.0.0" 347 | }, 348 | "engines": { 349 | "node": ">= 0.4" 350 | } 351 | }, 352 | "node_modules/typescript": { 353 | "version": "5.2.2", 354 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 355 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 356 | "dev": true, 357 | "bin": { 358 | "tsc": "bin/tsc", 359 | "tsserver": "bin/tsserver" 360 | }, 361 | "engines": { 362 | "node": ">=14.17" 363 | } 364 | }, 365 | "node_modules/undici-types": { 366 | "version": "5.25.3", 367 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", 368 | "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", 369 | "dev": true 370 | }, 371 | "node_modules/url": { 372 | "version": "0.10.3", 373 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 374 | "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", 375 | "dependencies": { 376 | "punycode": "1.3.2", 377 | "querystring": "0.2.0" 378 | } 379 | }, 380 | "node_modules/util": { 381 | "version": "0.12.5", 382 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", 383 | "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", 384 | "dependencies": { 385 | "inherits": "^2.0.3", 386 | "is-arguments": "^1.0.4", 387 | "is-generator-function": "^1.0.7", 388 | "is-typed-array": "^1.1.3", 389 | "which-typed-array": "^1.1.2" 390 | } 391 | }, 392 | "node_modules/uuid": { 393 | "version": "9.0.1", 394 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", 395 | "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", 396 | "funding": [ 397 | "https://github.com/sponsors/broofa", 398 | "https://github.com/sponsors/ctavan" 399 | ], 400 | "bin": { 401 | "uuid": "dist/bin/uuid" 402 | } 403 | }, 404 | "node_modules/which-typed-array": { 405 | "version": "1.1.13", 406 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", 407 | "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", 408 | "dependencies": { 409 | "available-typed-arrays": "^1.0.5", 410 | "call-bind": "^1.0.4", 411 | "for-each": "^0.3.3", 412 | "gopd": "^1.0.1", 413 | "has-tostringtag": "^1.0.0" 414 | }, 415 | "engines": { 416 | "node": ">= 0.4" 417 | }, 418 | "funding": { 419 | "url": "https://github.com/sponsors/ljharb" 420 | } 421 | }, 422 | "node_modules/xml2js": { 423 | "version": "0.5.0", 424 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", 425 | "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", 426 | "dependencies": { 427 | "sax": ">=0.6.0", 428 | "xmlbuilder": "~11.0.0" 429 | }, 430 | "engines": { 431 | "node": ">=4.0.0" 432 | } 433 | }, 434 | "node_modules/xmlbuilder": { 435 | "version": "11.0.1", 436 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 437 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", 438 | "engines": { 439 | "node": ">=4.0" 440 | } 441 | } 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /source/services/helper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cl-helper", 3 | "version": "4.0.2", 4 | "description": "helper function for Centralized Logging on AWS solution", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"nothing to do\"", 8 | "watch": "npx tsc -w", 9 | "preinstall": "cd ../@aws-solutions/utils && npm ci --production", 10 | "build:clean": "rm -rf ./node_modules && rm -rf ./dist", 11 | "build:ts": "npx tsc --project ./tsconfig.json", 12 | "build:copy": "cp -r ./node_modules ./dist/helper && cp -r ../@aws-solutions/utils/node_modules/* ./dist/helper/node_modules/ && cp ./dist/@aws-solutions/utils/*.js ./dist/helper/", 13 | "build:zip": "cd ./dist/helper && zip -r cl-helper.zip .", 14 | "build:all": "npm run build:clean && npm ci && npm run build:ts && npm prune --production && npm run build:copy && npm run build:zip" 15 | }, 16 | "author": "aws-solutions", 17 | "license": "Apache-2.0", 18 | "dependencies": { 19 | "uuid": "^9.0.0", 20 | "aws-sdk": "^2.1354.0" 21 | }, 22 | "devDependencies": { 23 | "typescript": "^5.1.3", 24 | "@types/uuid": "^9.0.2", 25 | "@types/node": "^20.3.1", 26 | "@types/aws-lambda": "^8.10.114" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/services/helper/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "noEmit": false, 6 | "baseUrl": ".", 7 | "paths": { 8 | "logger": ["../@aws-solutions/utils/logger"], 9 | "metric": ["../@aws-solutions/utils/metric"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /source/services/transformer/PromiseConstructor.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | export interface PromiseResolution { 4 | status: "fulfilled"; 5 | value: T; 6 | } 7 | 8 | export interface PromiseRejection { 9 | status: "rejected"; 10 | reason: E; 11 | } 12 | 13 | export type PromiseResult = 14 | | PromiseResolution 15 | | PromiseRejection; 16 | 17 | export type PromiseList = { 18 | [P in keyof T]: Promise; 19 | }; 20 | 21 | export type PromiseResultList = { 22 | [P in keyof T]: PromiseResult; 23 | }; 24 | 25 | declare global { 26 | interface PromiseConstructor { 27 | allSettled(): Promise<[]>; 28 | allSettled( 29 | list: PromiseList 30 | ): Promise>; 31 | allSettled(iterable: Iterable): Promise>>; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /source/services/transformer/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import zlib from "zlib"; 5 | import { Firehose } from "aws-sdk"; 6 | import { Record } from "aws-sdk/clients/firehose"; 7 | import { logger } from "logger"; 8 | import { sendUsageMetrics } from "metric"; 9 | 10 | /** 11 | * @description interface for log event 12 | * @property {string} id for the log event 13 | * @property {number} timestamp for the log event 14 | * @property {string} message stringified log event 15 | * @property {any} extractedFields inferred fields from the event 16 | */ 17 | interface ILogEvent { 18 | id: string; 19 | timestamp: number; 20 | message: string; 21 | extractedFields: any; 22 | } 23 | 24 | /** 25 | * @description interface for log event 26 | * @property {any[]} Records kinesis records from the data stream 27 | */ 28 | interface IEvent { 29 | Records: [ 30 | { 31 | kinesis: { 32 | kinesisSchemaVersion: string; 33 | partitionKey: string; 34 | sequenceNumber: string; 35 | data: string; 36 | approximateArrivalTimestamp: number; 37 | }; 38 | eventSource: string; 39 | eventVersion: string; 40 | eventID: string; 41 | eventName: string; 42 | invokeIdentityArn: string; 43 | awsRegion: string; 44 | eventSourceARN: string; 45 | } 46 | ]; 47 | } 48 | 49 | /** 50 | * @description transform log events into es documents 51 | * @param {ILogEvent} logEvent - log event to transform into es document 52 | * @param {string} owner - account id of the owner 53 | * @param {string} logGroup - log group originating the event 54 | * @param {string} logStream - log stream originating the event 55 | */ 56 | function transform( 57 | logEvent: ILogEvent, 58 | owner: string, 59 | logGroup: string, 60 | logStream: string 61 | ) { 62 | const source = buildSource(logEvent.message, logEvent.extractedFields); 63 | if ("requestParameters" in source) 64 | source["requestParameters"] = JSON.stringify(source["requestParameters"]); 65 | if ("responseElements" in source) 66 | source["responseElements"] = JSON.stringify(source["responseElements"]); 67 | if ("apiVersion" in source) source["apiVersion"] = "" + source["apiVersion"]; 68 | if ("account_id" in source) source["account_id"] = "" + source["account_id"]; 69 | source["timestamp"] = new Date(1 * logEvent.timestamp).toISOString(); 70 | source["id"] = logEvent.id; 71 | source["type"] = "CloudWatchLogs"; 72 | source["@message"] = logEvent.message; 73 | source["@owner"] = owner; 74 | source["@log_group"] = logGroup; 75 | source["@log_stream"] = logStream; 76 | 77 | return source; 78 | } 79 | 80 | /** 81 | * @description building source for log events 82 | * @param message - log event 83 | * @param extractedFields - fields in the log event 84 | */ 85 | function buildSource(message: string, extractedFields: any) { 86 | if (extractedFields) { 87 | logger.debug({ 88 | label: "handler", 89 | message: `extractedFields: ${extractedFields} `, 90 | }); 91 | const source: { [key: string]: any } = {}; 92 | 93 | for (const key in extractedFields) { 94 | if (extractedFields[key]) { 95 | const value = extractedFields[key]; 96 | if (isNumeric(value)) { 97 | source[key] = 1 * value; 98 | continue; 99 | } 100 | 101 | const _jsonSubString = extractJson(value); 102 | if (_jsonSubString !== null) { 103 | source["$" + key] = JSON.parse(_jsonSubString); 104 | } 105 | 106 | source[key] = value; 107 | } 108 | } 109 | 110 | return source; 111 | } 112 | 113 | logger.debug({ 114 | label: "handler", 115 | message: `message: ${message} `, 116 | }); 117 | const jsonSubString = extractJson(message); 118 | if (jsonSubString !== null) { 119 | return JSON.parse(jsonSubString); 120 | } 121 | 122 | return {}; 123 | } 124 | 125 | /** 126 | * @description extracting json from log event 127 | * @param {string} message - log event 128 | */ 129 | function extractJson(message: string) { 130 | const jsonStart = message.indexOf("{"); 131 | if (jsonStart < 0) return null; 132 | const jsonSubString = message.substring(jsonStart); 133 | return isValidJson(jsonSubString) ? jsonSubString : null; 134 | } 135 | 136 | /** 137 | * @description checking if extracted field has valid JSON 138 | * @param {string} message - log event 139 | */ 140 | function isValidJson(message: string) { 141 | try { 142 | JSON.parse(message); 143 | } catch (e) { 144 | return false; 145 | } 146 | return true; 147 | } 148 | 149 | /** 150 | * @description checking if extracted field has numeric value 151 | * @param n - extracted field to test for numeric value 152 | */ 153 | function isNumeric(n: any) { 154 | return !isNaN(parseFloat(n)) && isFinite(n); 155 | } 156 | 157 | function createRecordsFromEvents( 158 | logEvents: ILogEvent[], 159 | owner: string, 160 | logGroup: string, 161 | logStream: string 162 | ) { 163 | const records: Record[] = []; 164 | logEvents.forEach((event: ILogEvent) => { 165 | const transformedEvent = transform(event, owner, logGroup, logStream); 166 | logger.debug({ 167 | label: "createRecordsFromEvents", 168 | message: `transformed event: ${JSON.stringify(transformedEvent)}`, 169 | }); 170 | records.push({ 171 | Data: Buffer.from(JSON.stringify(transformedEvent)), 172 | }); 173 | }); 174 | logger.info({ 175 | label: "createRecordsFromEvents", 176 | message: "records created from log events", 177 | }); 178 | return records; 179 | } 180 | 181 | async function putRecords(records: Record[]) { 182 | logger.debug({ 183 | label: "putRecords", 184 | message: "records put on firehose", 185 | }); 186 | const params = { 187 | DeliveryStreamName: "" + process.env.DELIVERY_STREAM /* required */, 188 | Records: records, 189 | }; 190 | const firehose = new Firehose({ 191 | customUserAgent: process.env.CUSTOM_SDK_USER_AGENT, 192 | }); 193 | await firehose.putRecordBatch(params).promise(); 194 | 195 | if (process.env.SEND_METRIC === "Yes") { 196 | const recordLengths = records.map((it) => (it.Data as Buffer).byteLength); 197 | const summedItemSize = recordLengths.reduce((sum, next) => { 198 | return sum + next; 199 | }, 0); 200 | await sendUsageMetrics(summedItemSize); 201 | } 202 | } 203 | 204 | exports.handler = async (event: IEvent) => { 205 | logger.debug({ 206 | label: "handler", 207 | message: `event: ${JSON.stringify(event)}`, 208 | }); 209 | await Promise.allSettled( 210 | event.Records.map(async (r) => { 211 | try { 212 | const buffer = Buffer.from(r.kinesis.data, "base64"); 213 | let decompressed; 214 | try { 215 | decompressed = zlib.gunzipSync(buffer); 216 | } catch (e) { 217 | logger.error({ 218 | label: "handler", 219 | message: `error in reading data: ${JSON.stringify(e)} `, 220 | }); 221 | throw new Error("error in decompressing data"); 222 | } 223 | const payload = JSON.parse(decompressed.toString()); 224 | logger.debug({ label: "handler", message: JSON.stringify(payload) }); 225 | 226 | // CONTROL_MESSAGE are sent by CWL to check if the subscription is reachable. 227 | // They do not contain actual data. 228 | if (payload.messageType === "CONTROL_MESSAGE") { 229 | return; 230 | } else if (payload.messageType === "DATA_MESSAGE") { 231 | const records = createRecordsFromEvents( 232 | payload.logEvents, 233 | payload.owner, 234 | payload.logGroup, 235 | payload.logStream 236 | ); 237 | const chunkSize = 500; 238 | for (let i = 0; i < records.length; i += chunkSize) { 239 | const chunk = records.slice(i, i + chunkSize); 240 | await putRecords(chunk); 241 | logger.info({ 242 | label: "handler", 243 | message: `#${i}: ${chunk.length} records put success`, 244 | }); 245 | } 246 | } else { 247 | return; 248 | } 249 | } catch (e) { 250 | logger.error({ 251 | label: "handler", 252 | message: e, 253 | }); 254 | } 255 | }) 256 | ); 257 | }; 258 | -------------------------------------------------------------------------------- /source/services/transformer/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cl-transformer", 3 | "version": "4.0.2", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cl-transformer", 9 | "version": "4.0.2", 10 | "hasInstallScript": true, 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "aws-sdk": "^2.1354.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.3.1", 17 | "@types/uuid": "^9.0.2", 18 | "typescript": "^5.1.3" 19 | } 20 | }, 21 | "node_modules/@types/node": { 22 | "version": "20.8.7", 23 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", 24 | "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", 25 | "dev": true, 26 | "dependencies": { 27 | "undici-types": "~5.25.1" 28 | } 29 | }, 30 | "node_modules/@types/uuid": { 31 | "version": "9.0.6", 32 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", 33 | "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", 34 | "dev": true 35 | }, 36 | "node_modules/available-typed-arrays": { 37 | "version": "1.0.5", 38 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 39 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 40 | "engines": { 41 | "node": ">= 0.4" 42 | }, 43 | "funding": { 44 | "url": "https://github.com/sponsors/ljharb" 45 | } 46 | }, 47 | "node_modules/aws-sdk": { 48 | "version": "2.1477.0", 49 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1477.0.tgz", 50 | "integrity": "sha512-DLsrKosrKRe5P1E+BcJAVpOXkma4oUOrcyBUridDmUhdf9k3jj5dnL1roFuDpTmNDDhK8a1tUgY3wmXoKQtv7A==", 51 | "dependencies": { 52 | "buffer": "4.9.2", 53 | "events": "1.1.1", 54 | "ieee754": "1.1.13", 55 | "jmespath": "0.16.0", 56 | "querystring": "0.2.0", 57 | "sax": "1.2.1", 58 | "url": "0.10.3", 59 | "util": "^0.12.4", 60 | "uuid": "8.0.0", 61 | "xml2js": "0.5.0" 62 | }, 63 | "engines": { 64 | "node": ">= 10.0.0" 65 | } 66 | }, 67 | "node_modules/base64-js": { 68 | "version": "1.5.1", 69 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 70 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 71 | "funding": [ 72 | { 73 | "type": "github", 74 | "url": "https://github.com/sponsors/feross" 75 | }, 76 | { 77 | "type": "patreon", 78 | "url": "https://www.patreon.com/feross" 79 | }, 80 | { 81 | "type": "consulting", 82 | "url": "https://feross.org/support" 83 | } 84 | ] 85 | }, 86 | "node_modules/buffer": { 87 | "version": "4.9.2", 88 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 89 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 90 | "dependencies": { 91 | "base64-js": "^1.0.2", 92 | "ieee754": "^1.1.4", 93 | "isarray": "^1.0.0" 94 | } 95 | }, 96 | "node_modules/call-bind": { 97 | "version": "1.0.4", 98 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.4.tgz", 99 | "integrity": "sha512-e68w37XfAb5fL5M3NTxqKLcXRUkL2/kFlQjQjE/8jvPMBKmO5ZDycRkS/DrZRXjegOzwWzEwW88m+8r+D0PUUA==", 100 | "dependencies": { 101 | "function-bind": "^1.1.2", 102 | "get-intrinsic": "^1.2.1", 103 | "set-function-length": "^1.1.0" 104 | }, 105 | "funding": { 106 | "url": "https://github.com/sponsors/ljharb" 107 | } 108 | }, 109 | "node_modules/define-data-property": { 110 | "version": "1.1.1", 111 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", 112 | "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", 113 | "dependencies": { 114 | "get-intrinsic": "^1.2.1", 115 | "gopd": "^1.0.1", 116 | "has-property-descriptors": "^1.0.0" 117 | }, 118 | "engines": { 119 | "node": ">= 0.4" 120 | } 121 | }, 122 | "node_modules/events": { 123 | "version": "1.1.1", 124 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 125 | "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", 126 | "engines": { 127 | "node": ">=0.4.x" 128 | } 129 | }, 130 | "node_modules/for-each": { 131 | "version": "0.3.3", 132 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 133 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 134 | "dependencies": { 135 | "is-callable": "^1.1.3" 136 | } 137 | }, 138 | "node_modules/function-bind": { 139 | "version": "1.1.2", 140 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 141 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 142 | "funding": { 143 | "url": "https://github.com/sponsors/ljharb" 144 | } 145 | }, 146 | "node_modules/get-intrinsic": { 147 | "version": "1.2.1", 148 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", 149 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", 150 | "dependencies": { 151 | "function-bind": "^1.1.1", 152 | "has": "^1.0.3", 153 | "has-proto": "^1.0.1", 154 | "has-symbols": "^1.0.3" 155 | }, 156 | "funding": { 157 | "url": "https://github.com/sponsors/ljharb" 158 | } 159 | }, 160 | "node_modules/gopd": { 161 | "version": "1.0.1", 162 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 163 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 164 | "dependencies": { 165 | "get-intrinsic": "^1.1.3" 166 | }, 167 | "funding": { 168 | "url": "https://github.com/sponsors/ljharb" 169 | } 170 | }, 171 | "node_modules/has": { 172 | "version": "1.0.4", 173 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", 174 | "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", 175 | "engines": { 176 | "node": ">= 0.4.0" 177 | } 178 | }, 179 | "node_modules/has-property-descriptors": { 180 | "version": "1.0.0", 181 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 182 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 183 | "dependencies": { 184 | "get-intrinsic": "^1.1.1" 185 | }, 186 | "funding": { 187 | "url": "https://github.com/sponsors/ljharb" 188 | } 189 | }, 190 | "node_modules/has-proto": { 191 | "version": "1.0.1", 192 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 193 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 194 | "engines": { 195 | "node": ">= 0.4" 196 | }, 197 | "funding": { 198 | "url": "https://github.com/sponsors/ljharb" 199 | } 200 | }, 201 | "node_modules/has-symbols": { 202 | "version": "1.0.3", 203 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 204 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 205 | "engines": { 206 | "node": ">= 0.4" 207 | }, 208 | "funding": { 209 | "url": "https://github.com/sponsors/ljharb" 210 | } 211 | }, 212 | "node_modules/has-tostringtag": { 213 | "version": "1.0.0", 214 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 215 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 216 | "dependencies": { 217 | "has-symbols": "^1.0.2" 218 | }, 219 | "engines": { 220 | "node": ">= 0.4" 221 | }, 222 | "funding": { 223 | "url": "https://github.com/sponsors/ljharb" 224 | } 225 | }, 226 | "node_modules/ieee754": { 227 | "version": "1.1.13", 228 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 229 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 230 | }, 231 | "node_modules/inherits": { 232 | "version": "2.0.4", 233 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 234 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 235 | }, 236 | "node_modules/is-arguments": { 237 | "version": "1.1.1", 238 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 239 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 240 | "dependencies": { 241 | "call-bind": "^1.0.2", 242 | "has-tostringtag": "^1.0.0" 243 | }, 244 | "engines": { 245 | "node": ">= 0.4" 246 | }, 247 | "funding": { 248 | "url": "https://github.com/sponsors/ljharb" 249 | } 250 | }, 251 | "node_modules/is-callable": { 252 | "version": "1.2.7", 253 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 254 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 255 | "engines": { 256 | "node": ">= 0.4" 257 | }, 258 | "funding": { 259 | "url": "https://github.com/sponsors/ljharb" 260 | } 261 | }, 262 | "node_modules/is-generator-function": { 263 | "version": "1.0.10", 264 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", 265 | "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", 266 | "dependencies": { 267 | "has-tostringtag": "^1.0.0" 268 | }, 269 | "engines": { 270 | "node": ">= 0.4" 271 | }, 272 | "funding": { 273 | "url": "https://github.com/sponsors/ljharb" 274 | } 275 | }, 276 | "node_modules/is-typed-array": { 277 | "version": "1.1.12", 278 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", 279 | "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", 280 | "dependencies": { 281 | "which-typed-array": "^1.1.11" 282 | }, 283 | "engines": { 284 | "node": ">= 0.4" 285 | }, 286 | "funding": { 287 | "url": "https://github.com/sponsors/ljharb" 288 | } 289 | }, 290 | "node_modules/isarray": { 291 | "version": "1.0.0", 292 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 293 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" 294 | }, 295 | "node_modules/jmespath": { 296 | "version": "0.16.0", 297 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", 298 | "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", 299 | "engines": { 300 | "node": ">= 0.6.0" 301 | } 302 | }, 303 | "node_modules/punycode": { 304 | "version": "1.3.2", 305 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 306 | "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" 307 | }, 308 | "node_modules/querystring": { 309 | "version": "0.2.0", 310 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 311 | "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", 312 | "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", 313 | "engines": { 314 | "node": ">=0.4.x" 315 | } 316 | }, 317 | "node_modules/sax": { 318 | "version": "1.2.1", 319 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 320 | "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" 321 | }, 322 | "node_modules/set-function-length": { 323 | "version": "1.1.1", 324 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", 325 | "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", 326 | "dependencies": { 327 | "define-data-property": "^1.1.1", 328 | "get-intrinsic": "^1.2.1", 329 | "gopd": "^1.0.1", 330 | "has-property-descriptors": "^1.0.0" 331 | }, 332 | "engines": { 333 | "node": ">= 0.4" 334 | } 335 | }, 336 | "node_modules/typescript": { 337 | "version": "5.2.2", 338 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 339 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 340 | "dev": true, 341 | "bin": { 342 | "tsc": "bin/tsc", 343 | "tsserver": "bin/tsserver" 344 | }, 345 | "engines": { 346 | "node": ">=14.17" 347 | } 348 | }, 349 | "node_modules/undici-types": { 350 | "version": "5.25.3", 351 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", 352 | "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", 353 | "dev": true 354 | }, 355 | "node_modules/url": { 356 | "version": "0.10.3", 357 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 358 | "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", 359 | "dependencies": { 360 | "punycode": "1.3.2", 361 | "querystring": "0.2.0" 362 | } 363 | }, 364 | "node_modules/util": { 365 | "version": "0.12.5", 366 | "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", 367 | "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", 368 | "dependencies": { 369 | "inherits": "^2.0.3", 370 | "is-arguments": "^1.0.4", 371 | "is-generator-function": "^1.0.7", 372 | "is-typed-array": "^1.1.3", 373 | "which-typed-array": "^1.1.2" 374 | } 375 | }, 376 | "node_modules/uuid": { 377 | "version": "8.0.0", 378 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", 379 | "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", 380 | "bin": { 381 | "uuid": "dist/bin/uuid" 382 | } 383 | }, 384 | "node_modules/which-typed-array": { 385 | "version": "1.1.13", 386 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", 387 | "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", 388 | "dependencies": { 389 | "available-typed-arrays": "^1.0.5", 390 | "call-bind": "^1.0.4", 391 | "for-each": "^0.3.3", 392 | "gopd": "^1.0.1", 393 | "has-tostringtag": "^1.0.0" 394 | }, 395 | "engines": { 396 | "node": ">= 0.4" 397 | }, 398 | "funding": { 399 | "url": "https://github.com/sponsors/ljharb" 400 | } 401 | }, 402 | "node_modules/xml2js": { 403 | "version": "0.5.0", 404 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", 405 | "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", 406 | "dependencies": { 407 | "sax": ">=0.6.0", 408 | "xmlbuilder": "~11.0.0" 409 | }, 410 | "engines": { 411 | "node": ">=4.0.0" 412 | } 413 | }, 414 | "node_modules/xmlbuilder": { 415 | "version": "11.0.1", 416 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 417 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", 418 | "engines": { 419 | "node": ">=4.0" 420 | } 421 | } 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /source/services/transformer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cl-transformer", 3 | "version": "4.0.2", 4 | "description": "transformer lambda for Centralized Logging on AWS solution", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"nothing to do\"", 8 | "watch": "npx tsc -w", 9 | "preinstall": "cd ../@aws-solutions/utils && npm ci --production", 10 | "build:clean": "rm -rf ./node_modules && rm -rf ./dist", 11 | "build:ts": "npx tsc --project ./tsconfig.json", 12 | "build:copy": "cp -r ./node_modules ./dist/transformer && cp -r ../@aws-solutions/utils/node_modules/* ./dist/transformer/node_modules/ && cp -r ./dist/@aws-solutions/utils/*.js ./dist/transformer/", 13 | "build:zip": "cd ./dist/transformer && zip -r cl-transformer.zip .", 14 | "build:all": "npm run build:clean && npm ci && npm run build:ts && npm prune --production && npm run build:copy && npm run build:zip" 15 | }, 16 | "author": "aws-solutions", 17 | "license": "Apache-2.0", 18 | "dependencies": { 19 | "aws-sdk": "^2.1354.0" 20 | }, 21 | "devDependencies": { 22 | "typescript": "^5.1.3", 23 | "@types/uuid": "^9.0.2", 24 | "@types/node": "^20.3.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /source/services/transformer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "noEmit": false, 6 | "baseUrl": ".", 7 | "paths": { 8 | "logger": ["../@aws-solutions/utils/logger"], 9 | "metric": ["../@aws-solutions/utils/metric"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /source/services/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ES2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 5 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 6 | "lib": [ 7 | "DOM", 8 | "ES2018" 9 | ] /* Specify library files to be included in the compilation. */, 10 | "declaration": false /* Generates corresponding '.d.ts' file. */, 11 | "noEmit": true, 12 | "removeComments": true /* Do not emit comments to output. */, 13 | "resolveJsonModule": true /* Allows importing modules with a ‘.json’ extension */, 14 | /* Strict Type-Checking Options */ 15 | "strict": true /* Enable all strict type-checking options. */, 16 | "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 17 | // "strictNullChecks": true /* Enable strict null checks. */, 18 | "strictFunctionTypes": true /* Enable strict checking of function types. */, 19 | "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, 20 | "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, 21 | "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, 22 | 23 | /* Additional Checks */ 24 | "noUnusedLocals": true /* Report errors on unused locals. */, 25 | "noUnusedParameters": true /* Report errors on unused parameters. */, 26 | "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, 27 | "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, 28 | 29 | /* Module Resolution Options */ 30 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 31 | 32 | /* Experimental Options */ 33 | "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, 34 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 35 | 36 | /* Advanced Options */ 37 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 38 | }, 39 | "typedocOptions": { 40 | "includes": "./services/", 41 | "exclude": ["**/*+(.d.ts|.test.ts|node_modules)"], 42 | "mode": "modules", 43 | "externalPattern": ["**/resources/**", "**/deployment/**"], 44 | "excludeExternals": true, 45 | "ignoreCompilerErrors": true, 46 | "out": "docs", 47 | "includeVersion": true, 48 | "readMe": "./README.md" 49 | } 50 | } 51 | --------------------------------------------------------------------------------