-
Notifications
You must be signed in to change notification settings - Fork 249
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aws-iot-s3): new construct implementation (#469)
* aws-iot-s3 construt implementation * fix broken test * fix cfn_nag issues * update KMS Key test * fix pr comments * update test cases & address pr review comments * fix tests for cdk v2 * clean access logging buckets in integ tests * Used IBucket instead of Bucket as existing bucket prop * address pr review comments Co-authored-by: santhosh <>
- Loading branch information
Showing
14 changed files
with
1,617 additions
and
0 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
source/patterns/@aws-solutions-constructs/aws-iot-s3/.eslintignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
lib/*.js | ||
test/*.js | ||
*.d.ts | ||
coverage |
15 changes: 15 additions & 0 deletions
15
source/patterns/@aws-solutions-constructs/aws-iot-s3/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
lib/*.js | ||
test/*.js | ||
*.js.map | ||
*.d.ts | ||
node_modules | ||
*.generated.ts | ||
dist | ||
.jsii | ||
|
||
.LAST_BUILD | ||
.nyc_output | ||
coverage | ||
.nycrc | ||
.LAST_PACKAGE | ||
*.snk |
21 changes: 21 additions & 0 deletions
21
source/patterns/@aws-solutions-constructs/aws-iot-s3/.npmignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Exclude typescript source and config | ||
*.ts | ||
tsconfig.json | ||
coverage | ||
.nyc_output | ||
*.tgz | ||
*.snk | ||
*.tsbuildinfo | ||
|
||
# Include javascript files and typescript declarations | ||
!*.js | ||
!*.d.ts | ||
|
||
# Exclude jsii outdir | ||
dist | ||
|
||
# Include .jsii | ||
!.jsii | ||
|
||
# Include .jsii | ||
!.jsii |
106 changes: 106 additions & 0 deletions
106
source/patterns/@aws-solutions-constructs/aws-iot-s3/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# aws-iot-s3 module | ||
<!--BEGIN STABILITY BANNER--> | ||
|
||
--- | ||
|
||
![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) | ||
|
||
> All classes are under active development and subject to non-backward compatible changes or removal in any | ||
> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. | ||
> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. | ||
--- | ||
<!--END STABILITY BANNER--> | ||
|
||
| **Reference Documentation**:| <span style="font-weight: normal">https://docs.aws.amazon.com/solutions/latest/constructs/</span>| | ||
|:-------------|:-------------| | ||
<div style="height:8px"></div> | ||
|
||
| **Language** | **Package** | | ||
|:-------------|-----------------| | ||
|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_iot_s3`| | ||
|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-iot-s3`| | ||
|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.iots3`| | ||
|
||
This AWS Solutions Construct implements an AWS IoT MQTT topic rule and an Amazon S3 Bucket pattern. | ||
|
||
Here is a minimal deployable pattern definition in Typescript: | ||
|
||
``` typescript | ||
const { IotToS3Props, IotToS3 } from '@aws-solutions-constructs/aws-iot-s3'; | ||
|
||
const props: IotToS3Props = { | ||
iotTopicRuleProps: { | ||
topicRulePayload: { | ||
ruleDisabled: false, | ||
description: "Testing the IotToS3 Pattern", | ||
sql: "SELECT * FROM 'solutions/constructs'", | ||
actions: [] | ||
} | ||
} | ||
}; | ||
|
||
new IotToS3(this, 'test-iot-s3-integration', props); | ||
``` | ||
|
||
## Initializer | ||
|
||
``` text | ||
new IotToS3(scope: Construct, id: string, props: IotToS3Props); | ||
``` | ||
|
||
_Parameters_ | ||
|
||
* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html) | ||
* id `string` | ||
* props [`IotToS3Props`](#pattern-construct-props) | ||
|
||
## Pattern Construct Props | ||
|
||
| **Name** | **Type** | **Description** | | ||
|:-------------|:----------------|-----------------| | ||
|existingBucketInterface?|[`s3.IBucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.IBucket.html)|Existing S3 Bucket interface. Providing this property and `bucketProps` results in an error.| | ||
|bucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Bucket. Providing this and `existingBucketObj` reults in an error.| | ||
|loggingBucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Logging Bucket.| | ||
|iotTopicRuleProps?|[`iot.CfnTopicRuleProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRuleProps.html)|User provided CfnTopicRuleProps to override the defaults.| | ||
|s3Key|`string`|User provided s3Key to override the default (`${topic()}/${timestamp()}`) object key. Used to store messages matched by the IoT Rule.| | ||
|logS3AccessLogs?|`boolean`|Whether to turn on Access Logging for the S3 bucket. Creates an S3 bucket with associated storage costs for the logs. Enabling Access Logging is a best practice. default - true| | ||
|
||
## Pattern Properties | ||
|
||
| **Name** | **Type** | **Description** | | ||
|:-------------|:----------------|-----------------| | ||
|s3Bucket?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of the S3 bucket created by the pattern. If an existingBucketInterface is provided in IotToS3Props, then this value will be undefined| | ||
|s3BucketInterface?|[`s3.IBucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.IBucket.html)|Returns S3 Bucket interface created or used by the pattern. If an existingBucketInterface is provided in IotToS3Props, then only this value will be set and s3Bucket will be undefined. If the construct creates the bucket, then both properties will be set.| | ||
|s3LoggingBucket?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of `s3.Bucket` created by the construct as the logging bucket for the primary bucket.| | ||
|iotActionsRole|[`iam.Role`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iam.Role.html)|Returns an instance of `iam.Role` created by the construct, which allows IoT to publish messages to the S3 bucket.| | ||
|iotTopicRule|[`iot.CfnTopicRule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iot.CfnTopicRule.html)|Returns an instance of `iot.CfnTopicRule` created by the construct| | ||
|
||
## Default settings | ||
|
||
Out of the box implementation of the Construct without any override will set the following defaults: | ||
|
||
### Amazon IoT Rule | ||
|
||
* Configure an IoT Rule to send messages to the S3 Bucket | ||
|
||
### Amazon IAM Role | ||
|
||
* Configure least privilege access IAM role for Amazon IoT to be able to publish messages to the S3 Bucket | ||
|
||
### Amazon S3 Bucket | ||
|
||
* Configure Access logging for S3 Bucket | ||
* Enable server-side encryption for S3 Bucket using AWS managed KMS Key | ||
* Enforce encryption of data in transit | ||
* Turn on the versioning for S3 Bucket | ||
* Don't allow public access for S3 Bucket | ||
* Retain the S3 Bucket when deleting the CloudFormation stack | ||
* Applies Lifecycle rule to move noncurrent object versions to Glacier storage after 90 days | ||
|
||
## Architecture | ||
|
||
![Architecture Diagram](architecture.png) | ||
|
||
--- | ||
© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
Binary file added
BIN
+20.9 KB
source/patterns/@aws-solutions-constructs/aws-iot-s3/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
119 changes: 119 additions & 0 deletions
119
source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/** | ||
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance | ||
* with the License. A copy of the License is located at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES | ||
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions | ||
* and limitations under the License. | ||
*/ | ||
|
||
import * as s3 from '@aws-cdk/aws-s3'; | ||
import * as iot from '@aws-cdk/aws-iot'; | ||
import * as iam from '@aws-cdk/aws-iam'; | ||
import * as defaults from '@aws-solutions-constructs/core'; | ||
// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate | ||
import { Construct } from '@aws-cdk/core'; | ||
|
||
/** | ||
* @summary The properties for the IotToS3 class. | ||
*/ | ||
export interface IotToS3Props { | ||
/** | ||
* Existing S3 Bucket interface, providing both this and `bucketProps` will cause an error. | ||
* | ||
* @default - None | ||
*/ | ||
readonly existingBucketInterface?: s3.IBucket; | ||
/** | ||
* User provided props to override the default props for the S3 Bucket. | ||
* | ||
* @default - Default props are used. | ||
*/ | ||
readonly bucketProps?: s3.BucketProps; | ||
/** | ||
* User provided CfnTopicRuleProps to override the defaults | ||
* | ||
* @default - Default props are used. S3ActionProperty with S3 Key '${topic()}/${timestamp()}' is used. | ||
*/ | ||
readonly iotTopicRuleProps: iot.CfnTopicRuleProps; | ||
/** | ||
* Optional user provided props to override the default props for the S3 Logging Bucket. | ||
* | ||
* @default - Default props are used | ||
*/ | ||
readonly loggingBucketProps?: s3.BucketProps | ||
/** | ||
* Optional user provided value to override the default S3Key for IoTRule S3 Action. | ||
* | ||
* @default - Default value '${topic()}/${timestamp()}' is used | ||
*/ | ||
readonly s3Key?: string; | ||
/** | ||
* Whether to turn on Access Logs for the S3 bucket with the associated storage costs. | ||
* Enabling Access Logging is a best practice. | ||
* | ||
* @default - true | ||
*/ | ||
readonly logS3AccessLogs?: boolean; | ||
} | ||
|
||
export class IotToS3 extends Construct { | ||
public readonly s3Bucket?: s3.Bucket; | ||
public readonly s3BucketInterface: s3.IBucket; | ||
public readonly s3LoggingBucket?: s3.Bucket; | ||
public readonly iotActionsRole: iam.Role; | ||
public readonly iotTopicRule: iot.CfnTopicRule; | ||
|
||
/** | ||
* @summary Constructs a new instance of the IotToSqs class. | ||
* @param {cdk.App} scope - represents the scope for all the resources. | ||
* @param {string} id - this is a a scope-unique id. | ||
* @param {IotToS3Props} props - user provided props for the construct | ||
* @access public | ||
*/ | ||
constructor(scope: Construct, id: string, props: IotToS3Props) { | ||
super(scope, id); | ||
defaults.CheckProps(props); | ||
|
||
// Setup S3 Bucket | ||
if (!props.existingBucketInterface) { | ||
[this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { | ||
bucketProps: props.bucketProps, | ||
loggingBucketProps: props.loggingBucketProps, | ||
logS3AccessLogs: props.logS3AccessLogs | ||
}); | ||
this.s3BucketInterface = this.s3Bucket; | ||
} else { | ||
this.s3BucketInterface = props.existingBucketInterface; | ||
} | ||
|
||
// Role to allow IoT to send messages to the S3 Bucket | ||
this.iotActionsRole = new iam.Role(this, 'iot-actions-role', { | ||
assumedBy: new iam.ServicePrincipal('iot.amazonaws.com') | ||
}); | ||
|
||
// Setup the IAM policy for IoT Actions | ||
this.s3BucketInterface.grantWrite(this.iotActionsRole); | ||
|
||
const defaultIotTopicProps = defaults.DefaultCfnTopicRuleProps([{ | ||
s3: { | ||
key: props.s3Key || '${topic()}/${timestamp()}', | ||
bucketName: this.s3BucketInterface.bucketName, | ||
roleArn: this.iotActionsRole.roleArn | ||
} | ||
}]); | ||
const iotTopicProps = defaults.overrideProps(defaultIotTopicProps, props.iotTopicRuleProps, true); | ||
|
||
// Create the IoT topic rule | ||
this.iotTopicRule = new iot.CfnTopicRule(this, 'IotTopicRule', iotTopicProps); | ||
|
||
// If existing bucket has a KMS CMK, explicitly provide IoTActionsRole necessary access to write to the bucket | ||
if (this.s3Bucket && this.s3Bucket.encryptionKey) { | ||
this.s3Bucket.encryptionKey.grantEncrypt(this.iotActionsRole); | ||
} | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
source/patterns/@aws-solutions-constructs/aws-iot-s3/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
{ | ||
"name": "@aws-solutions-constructs/aws-iot-s3", | ||
"version": "0.0.0", | ||
"description": "CDK Constructs for AWS IoT to AWS S3 integration", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/awslabs/aws-solutions-constructs.git", | ||
"directory": "source/patterns/@aws-solutions-constructs/aws-iot-s3" | ||
}, | ||
"author": { | ||
"name": "Amazon Web Services", | ||
"url": "https://aws.amazon.com", | ||
"organization": true | ||
}, | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"build": "tsc -b .", | ||
"lint": "eslint -c ../eslintrc.yml --ext=.js,.ts . && tslint --project .", | ||
"lint-fix": "eslint -c ../eslintrc.yml --ext=.js,.ts --fix .", | ||
"test": "jest --coverage", | ||
"clean": "tsc -b --clean", | ||
"watch": "tsc -b -w", | ||
"integ": "cdk-integ", | ||
"integ-no-clean": "cdk-integ --no-clean", | ||
"integ-assert": "cdk-integ-assert", | ||
"jsii": "jsii", | ||
"jsii-pacmak": "jsii-pacmak", | ||
"build+lint+test": "npm run jsii && npm run lint && npm test && npm run integ-assert", | ||
"snapshot-update": "npm run jsii && npm test -- -u && npm run integ-assert" | ||
}, | ||
"jsii": { | ||
"outdir": "dist", | ||
"targets": { | ||
"java": { | ||
"package": "software.amazon.awsconstructs.services.iots3", | ||
"maven": { | ||
"groupId": "software.amazon.awsconstructs", | ||
"artifactId": "iots3" | ||
} | ||
}, | ||
"dotnet": { | ||
"namespace": "Amazon.Constructs.AWS.IotS3", | ||
"packageId": "Amazon.Constructs.AWS.IotS3", | ||
"signAssembly": true, | ||
"iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" | ||
}, | ||
"python": { | ||
"distName": "aws-solutions-constructs.aws-iot-s3", | ||
"module": "aws_solutions_constructs.aws_iot_s3" | ||
} | ||
} | ||
}, | ||
"dependencies": { | ||
"@aws-cdk/aws-iot": "0.0.0", | ||
"@aws-cdk/aws-s3": "0.0.0", | ||
"@aws-cdk/aws-iam": "0.0.0", | ||
"@aws-cdk/aws-kms": "0.0.0", | ||
"@aws-cdk/core": "0.0.0", | ||
"@aws-solutions-constructs/core": "0.0.0", | ||
"constructs": "^3.2.0" | ||
}, | ||
"devDependencies": { | ||
"@aws-cdk/assert": "0.0.0", | ||
"@types/jest": "^26.0.22", | ||
"@types/node": "^10.3.0" | ||
}, | ||
"jest": { | ||
"moduleFileExtensions": [ | ||
"js" | ||
], | ||
"coverageReporters": [ | ||
"text", | ||
[ | ||
"lcov", | ||
{ | ||
"projectRoot": "../../../../" | ||
} | ||
] | ||
] | ||
}, | ||
"peerDependencies": { | ||
"@aws-cdk/aws-iot": "0.0.0", | ||
"@aws-cdk/aws-s3": "0.0.0", | ||
"@aws-cdk/aws-iam": "0.0.0", | ||
"@aws-cdk/aws-kms": "0.0.0", | ||
"@aws-cdk/core": "0.0.0", | ||
"@aws-solutions-constructs/core": "0.0.0", | ||
"constructs": "^3.2.0" | ||
} | ||
} |
Oops, something went wrong.