From 501f607f43bfe80445c131ccad6a8d87a5b6f374 Mon Sep 17 00:00:00 2001 From: Sam Goodwin Date: Tue, 12 Jun 2018 01:51:08 -0700 Subject: [PATCH 1/3] aws-cdk-kinesis: Implement Kinesis Stream L2 construct with support for generated/user-supplied KMS encryption keys, and import/export across stacks --- packages/aws-cdk-all/package.json | 1 + packages/aws-cdk-kinesis/.gitignore | 6 + packages/aws-cdk-kinesis/.npmignore | 6 + packages/aws-cdk-kinesis/README.md | 101 ++ packages/aws-cdk-kinesis/lib/index.ts | 1 + packages/aws-cdk-kinesis/lib/stream.ts | 322 ++++++ packages/aws-cdk-kinesis/package.json | 48 + packages/aws-cdk-kinesis/test/test.stream.ts | 1049 ++++++++++++++++++ 8 files changed, 1534 insertions(+) create mode 100644 packages/aws-cdk-kinesis/.gitignore create mode 100644 packages/aws-cdk-kinesis/.npmignore create mode 100644 packages/aws-cdk-kinesis/README.md create mode 100644 packages/aws-cdk-kinesis/lib/index.ts create mode 100644 packages/aws-cdk-kinesis/lib/stream.ts create mode 100644 packages/aws-cdk-kinesis/package.json create mode 100644 packages/aws-cdk-kinesis/test/test.stream.ts diff --git a/packages/aws-cdk-all/package.json b/packages/aws-cdk-all/package.json index ee73b3234f0ec..d7b6d39f810d4 100644 --- a/packages/aws-cdk-all/package.json +++ b/packages/aws-cdk-all/package.json @@ -28,6 +28,7 @@ "aws-cdk-ec2": "^0.6.0", "aws-cdk-events": "^0.6.0", "aws-cdk-iam": "^0.6.0", + "aws-cdk-kinesis": "^0.6.0", "aws-cdk-kms": "^0.6.0", "aws-cdk-lambda": "^0.6.0", "aws-cdk-neptune": "^0.6.0", diff --git a/packages/aws-cdk-kinesis/.gitignore b/packages/aws-cdk-kinesis/.gitignore new file mode 100644 index 0000000000000..4a14c934cd873 --- /dev/null +++ b/packages/aws-cdk-kinesis/.gitignore @@ -0,0 +1,6 @@ +*.js +*.js.map +*.d.ts +node_modules +dist +tsconfig.json diff --git a/packages/aws-cdk-kinesis/.npmignore b/packages/aws-cdk-kinesis/.npmignore new file mode 100644 index 0000000000000..414172bb772ec --- /dev/null +++ b/packages/aws-cdk-kinesis/.npmignore @@ -0,0 +1,6 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz diff --git a/packages/aws-cdk-kinesis/README.md b/packages/aws-cdk-kinesis/README.md new file mode 100644 index 0000000000000..a5cb5e80b2da2 --- /dev/null +++ b/packages/aws-cdk-kinesis/README.md @@ -0,0 +1,101 @@ +## AWS Kinesis Construct Library + +Define an unencrypted Kinesis stream. + +```ts +new Stream(this, 'MyFirstStream'); +``` + +### Encryption + +Define a KMS-encrypted stream: + +```ts +const stream = newStream(this, 'MyEncryptedStream', { + encryption: StreamEncryption.Kms +}); + +// you can access the encryption key: +assert(stream.encryptionKey instanceof kms.EncryptionKey); +``` + +You can also supply your own key: + +```ts +const myKmsKey = new kms.EncryptionKey(this, 'MyKey'); + +const stream = new Stream(this, 'MyEncryptedStream', { + encryption: StreamEncryption.Kms, + encryptionKey: myKmsKey +}); + +assert(stream.encryptionKey === myKmsKey); +``` + +### Importing and Exporting Streams + +You can create a `Stream` construct that represents an external/existing/unowned stream by using the `Stream.import` factory method. + +This method accepts an object that adheres to `StreamRef`. + +This means that you can define a `StreamRef` using token literals: + +```ts +const stream = Stream.import(this, { + streamArn: new StreamArn('arn:aws:kinesis:us-east-1:123456789012:stream/example-stream-name') +}); + +// now you can just call methods on the stream +stream.grantReadWrite(user); +``` + +The `stream.export()` method can be used to "export" the stream from the current stack. It returns a `StreamRef` object that can later be used in a call to `Stream.import` in another stack. + +Here's an example. + +Let's define a stack with a Kinesis stream and export it using `stream.export()`. + +```ts +class Producer extends Stack { + public readonly myStreamRef: StreamRef; + + constructor(parent: App, name: string) { + super(parent, name); + + const stream = new Stream(this, 'MyStream'); + this.myStreamRef = stream.export(); + } +} +``` + +Now let's define a stack that requires a StreamRef as an input and uses `Stream.import` to create a `Stream` object that represents this external stream. Grant a user principal created within this consuming stack read/write permissions to the stream. + +```ts +interface ConsumerProps { + public userStreamRef: StreamRef; +} + +class Consumer extends Stack { + constructor(parent: App, name: string, props: ConsumerProps) { + super(parent, name); + + const user = new User(this, 'MyUser'); + const userStream = Stream.import(this, props.userStreamRef); + userStream.grantReadWrite(user); + } +} +``` + +Now, let's define our CDK app to bind these together: + +```ts +const app = new App(process.argv); + +const producer = new Producer(app, 'produce'); + +new Consumer(app, 'consume', { + userStreamRef: producer.myStreamRef +}); + +process.stdout.write(app.run()); +``` diff --git a/packages/aws-cdk-kinesis/lib/index.ts b/packages/aws-cdk-kinesis/lib/index.ts new file mode 100644 index 0000000000000..3b1a34eb6fcb1 --- /dev/null +++ b/packages/aws-cdk-kinesis/lib/index.ts @@ -0,0 +1 @@ +export * from './stream'; diff --git a/packages/aws-cdk-kinesis/lib/stream.ts b/packages/aws-cdk-kinesis/lib/stream.ts new file mode 100644 index 0000000000000..9f2975767dade --- /dev/null +++ b/packages/aws-cdk-kinesis/lib/stream.ts @@ -0,0 +1,322 @@ +import { Construct, Output, PolicyStatement, Tag, Token } from 'aws-cdk'; +import { IIdentityResource } from 'aws-cdk-iam'; +import * as kms from 'aws-cdk-kms'; +import { kinesis } from 'aws-cdk-resources'; + +/** + * A reference to a stream. The easiest way to instantiate is to call + * `stream.export()`. Then, the consumer can use `Stream.import(this, ref)` and + * get a `Stream`. + */ +export interface StreamRefProps { + /** + * The ARN of the stream. + */ + streamArn: kinesis.StreamArn; + + /** + * The KMS key securing the contents of the stream if encryption is enabled. + */ + encryptionKey?: kms.EncryptionKeyRefProps; +} + +/** + * Represents a Kinesis Stream. + * + * Streams can be either defined within this stack: + * + * new Stream(this, 'MyStream', { props }); + * + * Or imported from an existing stream: + * + * StreamRef.import(this, 'MyImportedStream', { streamArn: ... }); + * + * You can also export a stream and import it into another stack: + * + * const ref = myStream.export(); + * StreamRef.import(this, 'MyImportedStream', ref); + * + */ +export abstract class StreamRef extends Construct { + /** + * Creates a Stream construct that represents an external stream. + * + * @param parent The parent creating construct (usually `this`). + * @param name The construct's name. + * @param ref A StreamRefProps object. Can be obtained from a call to + * `stream.export()`. + */ + public static import(parent: Construct, name: string, props: StreamRefProps): StreamRef { + return new ImportedStreamRef(parent, name, props); + } + + /** + * The ARN of the stream. + */ + public abstract readonly streamArn: kinesis.StreamArn; + + /** + * Optional KMS encryption key associated with this stream. + */ + public abstract readonly encryptionKey?: kms.EncryptionKeyRef; + + /** + * Exports this stream from the stack. + */ + public export(): StreamRefProps { + const streamArn = new Output(this, 'StreamArn', { value: this.streamArn }).makeImportValue(); + if (this.encryptionKey) { + return { + streamArn, + encryptionKey: this.encryptionKey.export() + }; + } else { + return { streamArn }; + } + } + + /** + * Grant write permissions for this stream and it's contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to ues the key to decrypt the + * contents of the stream will also be granted. + */ + public grantRead(identity?: IIdentityResource) { + if (!identity) { + return; + } + this.grant( + identity, + [ + 'kinesis:DescribeStream', + 'kinesis:GetRecords', + 'kinesis:GetShardIterator' + ], + [ + 'kms:Decrypt' + ] + ); + } + + /** + * Grant read permissions for this stream and it's contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to ues the key to decrypt the + * contents of the stream will also be granted. + */ + public grantWrite(identity?: IIdentityResource) { + if (!identity) { + return; + } + + this.grant( + identity, + [ + 'kinesis:DescribeStream', + 'kinesis:PutRecord', + 'kinesis:PutRecords' + ], + [ + 'kms:GenerateDataKey', + 'kms:Encrypt' + ] + ); + } + + /** + * Grants read/write permissions for this stream and it's contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to use the key for + * encrypt/decrypt will also be granted. + */ + public grantReadWrite(identity?: IIdentityResource) { + if (!identity) { + return; + } + this.grant( + identity, + [ + 'kinesis:DescribeStream', + 'kinesis:GetRecords', + 'kinesis:GetShardIterator', + 'kinesis:PutRecord', + 'kinesis:PutRecords' + ], + [ + 'kms:Decrypt', + 'kms:GenerateDataKey', + 'kms:Encrypt' + ] + ); + } + + private grant(identity: IIdentityResource, streamActions: string[], keyActions: string[]) { + identity.addToPolicy(new PolicyStatement() + .addResource(this.streamArn) + .addActions(...streamActions)); + + // grant key permissions if there's an associated key. + if (this.encryptionKey) { + identity.addToPolicy(new PolicyStatement() + .addResource(this.encryptionKey.keyArn) + .addActions(...keyActions)); + } + } +} + +export interface StreamProps { + /** + * Enforces a particular physical stream name. + * @default + */ + streamName?: string; + + /** + * The number of hours for the data records that are stored in shards to remain accessible. + * @default 24 + */ + retentionPeriodHours?: number; + + /** + * The number of shards for the stream. + * @default 1 + */ + shardCount?: number; + + /** + * The kind of server-side encryption to apply to this stream. + * + * If you choose KMS, you can specify a KMS key via `encryptionKey`. If + * encryption key is not specified, a key will automatically be created. + * + * @default Unencrypted + */ + encryption?: StreamEncryption; + + /** + * External KMS key to use for stream encryption. + * + * The 'encryption' property must be set to "Kms". + * + * @default If encryption is set to "Kms" and this property is undefined, a + * new KMS key will be created and associated with this stream. + */ + encryptionKey?: kms.EncryptionKeyRef; + + /** + * An arbitrary set of tags (key–value pairs) to associate with the Kinesis stream. + */ + tags?: Array | Token; +} + +/** + * A Kinesis stream. Can be encrypted with a KMS key. + */ +export class Stream extends StreamRef { + public readonly streamArn: kinesis.StreamArn; + public readonly streamName: StreamName; + public readonly encryptionKey?: kms.EncryptionKeyRef; + + private readonly stream: kinesis.StreamResource; + + constructor(parent: Construct, name: string, props: StreamProps = {}) { + super(parent, name); + + const shardCount = props.shardCount || 1; + const retentionPeriodHours = props.retentionPeriodHours || 24; + if (retentionPeriodHours < 24 && retentionPeriodHours > 168) { + throw new Error("retentionPeriodHours must be between 24 and 168 hours"); + } + + const { streamEncryption, encryptionKey } = this.parseEncryption(props); + + this.stream = new kinesis.StreamResource(this, "Resource", { + streamName: props.streamName, + retentionPeriodHours, + shardCount, + streamEncryption, + tags: props.tags + }); + this.streamArn = this.stream.streamArn; + this.streamName = this.stream.ref; + this.encryptionKey = encryptionKey; + + if (props.streamName) { this.addMetadata('aws:cdk:hasPhysicalName', props.streamName); } + } + + /** + * Set up key properties and return the Stream encryption property from the + * user's configuration. + */ + private parseEncryption(props: StreamProps): { + streamEncryption?: kinesis.StreamResource.StreamEncryptionProperty, + encryptionKey?: kms.EncryptionKeyRef + } { + + // default to unencrypted. + const encryptionType = props.encryption || StreamEncryption.Unencrypted; + + // if encryption key is set, encryption must be set to KMS. + if (encryptionType !== StreamEncryption.Kms && props.encryptionKey) { + throw new Error(`encryptionKey is specified, so 'encryption' must be set to KMS (value: ${encryptionType})`); + } + + if (encryptionType === StreamEncryption.Unencrypted) { + return { streamEncryption: undefined, encryptionKey: undefined }; + } + + if (encryptionType === StreamEncryption.Kms) { + const encryptionKey = props.encryptionKey || new kms.EncryptionKey(this, 'Key', { + description: `Created by ${this.path}` + }); + + const streamEncryption: kinesis.StreamResource.StreamEncryptionProperty = { + encryptionType: 'KMS', + keyId: encryptionKey.keyArn + }; + return { encryptionKey, streamEncryption }; + } + + throw new Error(`Unexpected 'encryptionType': ${encryptionType}`); + } +} + +/** + * What kind of server-side encryption to apply to this stream + */ +export enum StreamEncryption { + /** + * Records in the stream are not encrypted. + */ + Unencrypted = 'NONE', + + /** + * Server-side encryption with a KMS key managed by the user. + * If `encryptionKey` is specified, this key will be used, otherwise, one will be defined. + */ + Kms = 'KMS', +} + +/** + * The name of the stream. + */ +export class StreamName extends Token {} + +class ImportedStreamRef extends StreamRef { + public readonly streamArn: kinesis.StreamArn; + public readonly encryptionKey?: kms.EncryptionKeyRef; + + constructor(parent: Construct, name: string, props: StreamRefProps) { + super(parent, name); + + this.streamArn = props.streamArn; + if (props.encryptionKey) { + this.encryptionKey = kms.EncryptionKeyRef.import(parent, 'Key', props.encryptionKey); + } else { + this.encryptionKey = undefined; + } + } +} diff --git a/packages/aws-cdk-kinesis/package.json b/packages/aws-cdk-kinesis/package.json new file mode 100644 index 0000000000000..47884f9ef5d75 --- /dev/null +++ b/packages/aws-cdk-kinesis/package.json @@ -0,0 +1,48 @@ +{ + "name": "aws-cdk-kinesis", + "version": "0.6.0", + "description": "CDK Constructs for AWS Kinesis", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "bundledDependencies": [], + "names": { + "java": "com.amazonaws.cdk.kinesis", + "dotnet": "Aws.Cdk.Kinesis" + } + }, + "repository": { + "type": "git", + "url": "git://github.com/awslabs/aws-cdk" + }, + "scripts": { + "prepare": "jsii && tslint -p . && pkglint", + "watch": "jsii -w", + "lint": "tsc && tslint -p . --force", + "test": "nodeunit test/test.*.js", + "pkglint": "pkglint -f" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "kinesis" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "license": "Apache-2.0", + "devDependencies": { + "aws-cdk-assert": "^0.6.0", + "aws-cdk-toolkit": "^0.6.0", + "pkglint": "^0.6.0" + }, + "dependencies": { + "aws-cdk": "^0.6.0", + "aws-cdk-iam": "^0.6.0", + "aws-cdk-kms": "^0.6.0", + "aws-cdk-resources": "^0.6.0" + } +} diff --git a/packages/aws-cdk-kinesis/test/test.stream.ts b/packages/aws-cdk-kinesis/test/test.stream.ts new file mode 100644 index 0000000000000..9807b43d39aa7 --- /dev/null +++ b/packages/aws-cdk-kinesis/test/test.stream.ts @@ -0,0 +1,1049 @@ +import { Stack } from 'aws-cdk'; +import { expect } from 'aws-cdk-assert'; +import { User } from 'aws-cdk-iam'; +import { EncryptionKey } from 'aws-cdk-kms'; +import { Test } from 'nodeunit'; +import { Stream, StreamEncryption } from '../lib'; + +// tslint:disable:object-literal-key-quotes + +export = { + 'default stream'(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream'); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1 + } + } + } + }); + + test.done(); + }, + "uses explicit shard count"(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream', { + shardCount: 2 + }); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 2 + } + } + } + }); + + test.done(); + }, + "uses explicit retention period"(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream', { + retentionPeriodHours: 168 + }); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 168, + "ShardCount": 1 + } + } + } + }); + + test.done(); + }, + "retention period must be between 24 and 168 hours"(test: Test) { + test.throws({ + block: () => { + new Stream(new Stack(), 'MyStream', { + retentionPeriodHours: 169 + }); + }, + message: "retentionPeriodHours must be between 24 and 168 hours" + }); + + test.throws({ + block: () => { + new Stream(new Stack(), 'MyStream', { + retentionPeriodHours: 23 + }); + }, + message: "retentionPeriodHours must be between 24 and 168 hours" + }); + + test.done(); + }, + "attaches tags to stream"(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream', { + tags: [{ + key: "key", + value: "value" + }] + }); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "Tags": [ + { + "Key": "key", + "Value": "value" + } + ] + } + } + } + }); + + test.done(); + }, + "auto-creates KMS key if encryption type is KMS but no key is provided"(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream', { + encryption: StreamEncryption.Kms + }); + + expect(stack).toMatch({ + "Resources": { + "MyStreamKey76F3300E": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by MyStream", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + } + } + } + }); + + test.done(); + }, + "uses explicit KMS key if encryption type is KMS and a key is provided"(test: Test) { + const stack = new Stack(); + + const explicitKey = new EncryptionKey(stack, 'ExplicitKey', { + description: `Explicit Key` + }); + + new Stream(stack, 'MyStream', { + encryption: StreamEncryption.Kms, + encryptionKey: explicitKey + }); + + expect(stack).toMatch({ + "Resources": { + "ExplicitKey7DF42F37": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Explicit Key", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "ExplicitKey7DF42F37", + "Arn" + ] + } + } + } + } + } + }); + + test.done(); + }, + "permissions": { + "with encryption": { + "grantRead creates and attaches a policy with read only access to Stream and EncryptionKey"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.Kms + }); + + const user = new User(stack, "MyUser"); + stream.grantRead(user); + + expect(stack).toMatch({ + "Resources": { + "MyStreamKey76F3300E": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by MyStream", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + }, + { + "Action": "kms:Decrypt", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + }, + "grantWrite creates and attaches a policy with write only access to Stream and EncryptionKey"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.Kms + }); + + const user = new User(stack, "MyUser"); + stream.grantWrite(user); + + expect(stack).toMatch({ + "Resources": { + "MyStreamKey76F3300E": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by MyStream", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + }, + { + "Action": [ + "kms:GenerateDataKey", + "kms:Encrypt" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + }, + "grantReadWrite creates and attaches a policy with access to Stream and EncryptionKey"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.Kms + }); + + const user = new User(stack, "MyUser"); + stream.grantReadWrite(user); + + expect(stack).toMatch({ + "Resources": { + "MyStreamKey76F3300E": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by MyStream", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + }, + { + "Action": [ + "kms:Decrypt", + "kms:GenerateDataKey", + "kms:Encrypt" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + } + }, + "with no encryption": { + "grantRead creates and associates a policy with read only access to Stream"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream'); + + const user = new User(stack, "MyUser"); + stream.grantRead(user); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1 + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + }, + "grantWrite creates and attaches a policy with write only access to Stream"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream'); + + const user = new User(stack, "MyUser"); + stream.grantWrite(user); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1 + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + }, + "greatReadWrite creates and attaches a policy with write only access to Stream"(test: Test) { + const stack = new Stack(); + const stream = new Stream(stack, 'MyStream'); + + const user = new User(stack, "MyUser"); + stream.grantReadWrite(user); + + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1 + } + }, + "MyUserDC45028B": { + "Type": "AWS::IAM::User" + }, + "MyUserDefaultPolicy7B897426": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyUserDefaultPolicy7B897426", + "Users": [ + { + "Ref": "MyUserDC45028B" + } + ] + } + } + } + }); + + test.done(); + } + } + }, + "cross-stack permissions": { + "no encryption"(test: Test) { + const stackA = new Stack(); + const streamFromStackA = new Stream(stackA, 'MyStream'); + const refToStreamFromStackA = streamFromStackA.export(); + + const stackB = new Stack(); + const user = new User(stackB, 'UserWhoNeedsAccess'); + const theStreamFromStackAAsARefInStackB = Stream.import(stackB, 'RefToStreamFromStackA', refToStreamFromStackA); + theStreamFromStackAAsARefInStackB.grantRead(user); + + expect(stackA).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1 + } + } + }, + "Outputs": { + "MyStreamStreamArn495BAFC1": { + "Value": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + }, + "Export": { + "Name": "MyStreamStreamArn495BAFC1" + } + } + } + }); + + expect(stackB).toMatch({ + "Resources": { + "UserWhoNeedsAccessF8959C3D": { + "Type": "AWS::IAM::User" + }, + "UserWhoNeedsAccessDefaultPolicy6A9EB530": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator" + ], + "Effect": "Allow", + "Resource": { + "Fn::ImportValue": "MyStreamStreamArn495BAFC1" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "UserWhoNeedsAccessDefaultPolicy6A9EB530", + "Users": [ + { + "Ref": "UserWhoNeedsAccessF8959C3D" + } + ] + } + } + } + }); + + test.done(); + }, + "with encryption"(test: Test) { + const stackA = new Stack(); + const streamFromStackA = new Stream(stackA, 'MyStream', { + encryption: StreamEncryption.Kms + }); + const refToStreamFromStackA = streamFromStackA.export(); + + const stackB = new Stack(); + const user = new User(stackB, 'UserWhoNeedsAccess'); + const theStreamFromStackAAsARefInStackB = Stream.import(stackB, 'RefToStreamFromStackA', refToStreamFromStackA); + theStreamFromStackAAsARefInStackB.grantRead(user); + + expect(stackA).toMatch({ + "Resources": { + "MyStreamKey76F3300E": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by MyStream", + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Retain" + }, + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": { + "Fn::GetAtt": [ + "MyStreamKey76F3300E", + "Arn" + ] + } + } + } + } + }, + "Outputs": { + "MyStreamKeyKeyArn967BCB03": { + "Export": { + "Name": "MyStreamKeyKeyArn967BCB03" + } + }, + "MyStreamStreamArn495BAFC1": { + "Value": { + "Fn::GetAtt": [ + "MyStream5C050E93", + "Arn" + ] + }, + "Export": { + "Name": "MyStreamStreamArn495BAFC1" + } + } + } + }); + + expect(stackB).toMatch({ + "Resources": { + "UserWhoNeedsAccessF8959C3D": { + "Type": "AWS::IAM::User" + }, + "UserWhoNeedsAccessDefaultPolicy6A9EB530": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:DescribeStream", + "kinesis:GetRecords", + "kinesis:GetShardIterator" + ], + "Effect": "Allow", + "Resource": { + "Fn::ImportValue": "MyStreamStreamArn495BAFC1" + } + }, + { + "Action": "kms:Decrypt", + "Effect": "Allow", + "Resource": { + "Fn::ImportValue": "MyStreamKeyKeyArn967BCB03" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "UserWhoNeedsAccessDefaultPolicy6A9EB530", + "Users": [ + { + "Ref": "UserWhoNeedsAccessF8959C3D" + } + ] + } + } + } + }); + + test.done(); + } + } +}; \ No newline at end of file From 10515f21fb6a2488ea703ee7ff7eccb40590e3be Mon Sep 17 00:00:00 2001 From: Sam Goodwin Date: Tue, 12 Jun 2018 22:05:43 -0700 Subject: [PATCH 2/3] Remove import from README. Remove tags. Update .gitignore --- packages/aws-cdk-kinesis/.gitignore | 1 + packages/aws-cdk-kinesis/README.md | 68 ---------------- packages/aws-cdk-kinesis/lib/stream.ts | 86 ++++++++++---------- packages/aws-cdk-kinesis/test/test.stream.ts | 30 ------- 4 files changed, 44 insertions(+), 141 deletions(-) diff --git a/packages/aws-cdk-kinesis/.gitignore b/packages/aws-cdk-kinesis/.gitignore index 4a14c934cd873..026a6f10e3d47 100644 --- a/packages/aws-cdk-kinesis/.gitignore +++ b/packages/aws-cdk-kinesis/.gitignore @@ -4,3 +4,4 @@ node_modules dist tsconfig.json +tslint.json diff --git a/packages/aws-cdk-kinesis/README.md b/packages/aws-cdk-kinesis/README.md index a5cb5e80b2da2..19424d44e7193 100644 --- a/packages/aws-cdk-kinesis/README.md +++ b/packages/aws-cdk-kinesis/README.md @@ -31,71 +31,3 @@ const stream = new Stream(this, 'MyEncryptedStream', { assert(stream.encryptionKey === myKmsKey); ``` - -### Importing and Exporting Streams - -You can create a `Stream` construct that represents an external/existing/unowned stream by using the `Stream.import` factory method. - -This method accepts an object that adheres to `StreamRef`. - -This means that you can define a `StreamRef` using token literals: - -```ts -const stream = Stream.import(this, { - streamArn: new StreamArn('arn:aws:kinesis:us-east-1:123456789012:stream/example-stream-name') -}); - -// now you can just call methods on the stream -stream.grantReadWrite(user); -``` - -The `stream.export()` method can be used to "export" the stream from the current stack. It returns a `StreamRef` object that can later be used in a call to `Stream.import` in another stack. - -Here's an example. - -Let's define a stack with a Kinesis stream and export it using `stream.export()`. - -```ts -class Producer extends Stack { - public readonly myStreamRef: StreamRef; - - constructor(parent: App, name: string) { - super(parent, name); - - const stream = new Stream(this, 'MyStream'); - this.myStreamRef = stream.export(); - } -} -``` - -Now let's define a stack that requires a StreamRef as an input and uses `Stream.import` to create a `Stream` object that represents this external stream. Grant a user principal created within this consuming stack read/write permissions to the stream. - -```ts -interface ConsumerProps { - public userStreamRef: StreamRef; -} - -class Consumer extends Stack { - constructor(parent: App, name: string, props: ConsumerProps) { - super(parent, name); - - const user = new User(this, 'MyUser'); - const userStream = Stream.import(this, props.userStreamRef); - userStream.grantReadWrite(user); - } -} -``` - -Now, let's define our CDK app to bind these together: - -```ts -const app = new App(process.argv); - -const producer = new Producer(app, 'produce'); - -new Consumer(app, 'consume', { - userStreamRef: producer.myStreamRef -}); - -process.stdout.write(app.run()); -``` diff --git a/packages/aws-cdk-kinesis/lib/stream.ts b/packages/aws-cdk-kinesis/lib/stream.ts index 9f2975767dade..42ad746dd0d19 100644 --- a/packages/aws-cdk-kinesis/lib/stream.ts +++ b/packages/aws-cdk-kinesis/lib/stream.ts @@ -1,4 +1,4 @@ -import { Construct, Output, PolicyStatement, Tag, Token } from 'aws-cdk'; +import { Construct, Output, PolicyStatement, Token } from 'aws-cdk'; import { IIdentityResource } from 'aws-cdk-iam'; import * as kms from 'aws-cdk-kms'; import { kinesis } from 'aws-cdk-resources'; @@ -76,7 +76,7 @@ export abstract class StreamRef extends Construct { } /** - * Grant write permissions for this stream and it's contents to an IAM + * Grant write permissions for this stream and its contents to an IAM * principal (Role/Group/User). * * If an encryption key is used, permission to ues the key to decrypt the @@ -88,19 +88,21 @@ export abstract class StreamRef extends Construct { } this.grant( identity, - [ - 'kinesis:DescribeStream', - 'kinesis:GetRecords', - 'kinesis:GetShardIterator' - ], - [ - 'kms:Decrypt' - ] + { + streamActions: [ + 'kinesis:DescribeStream', + 'kinesis:GetRecords', + 'kinesis:GetShardIterator' + ], + keyActions: [ + 'kms:Decrypt' + ] + } ); } /** - * Grant read permissions for this stream and it's contents to an IAM + * Grant read permissions for this stream and its contents to an IAM * principal (Role/Group/User). * * If an encryption key is used, permission to ues the key to decrypt the @@ -113,20 +115,22 @@ export abstract class StreamRef extends Construct { this.grant( identity, - [ - 'kinesis:DescribeStream', - 'kinesis:PutRecord', - 'kinesis:PutRecords' - ], - [ - 'kms:GenerateDataKey', - 'kms:Encrypt' - ] + { + streamActions: [ + 'kinesis:DescribeStream', + 'kinesis:PutRecord', + 'kinesis:PutRecords' + ], + keyActions: [ + 'kms:GenerateDataKey', + 'kms:Encrypt' + ] + } ); } /** - * Grants read/write permissions for this stream and it's contents to an IAM + * Grants read/write permissions for this stream and its contents to an IAM * principal (Role/Group/User). * * If an encryption key is used, permission to use the key for @@ -138,31 +142,33 @@ export abstract class StreamRef extends Construct { } this.grant( identity, - [ - 'kinesis:DescribeStream', - 'kinesis:GetRecords', - 'kinesis:GetShardIterator', - 'kinesis:PutRecord', - 'kinesis:PutRecords' - ], - [ - 'kms:Decrypt', - 'kms:GenerateDataKey', - 'kms:Encrypt' - ] + { + streamActions: [ + 'kinesis:DescribeStream', + 'kinesis:GetRecords', + 'kinesis:GetShardIterator', + 'kinesis:PutRecord', + 'kinesis:PutRecords' + ], + keyActions: [ + 'kms:Decrypt', + 'kms:GenerateDataKey', + 'kms:Encrypt' + ] + } ); } - private grant(identity: IIdentityResource, streamActions: string[], keyActions: string[]) { + private grant(identity: IIdentityResource, actions: { streamActions: string[], keyActions: string[] }) { identity.addToPolicy(new PolicyStatement() .addResource(this.streamArn) - .addActions(...streamActions)); + .addActions(...actions.streamActions)); // grant key permissions if there's an associated key. if (this.encryptionKey) { identity.addToPolicy(new PolicyStatement() .addResource(this.encryptionKey.keyArn) - .addActions(...keyActions)); + .addActions(...actions.keyActions)); } } } @@ -205,11 +211,6 @@ export interface StreamProps { * new KMS key will be created and associated with this stream. */ encryptionKey?: kms.EncryptionKeyRef; - - /** - * An arbitrary set of tags (key–value pairs) to associate with the Kinesis stream. - */ - tags?: Array | Token; } /** @@ -237,8 +238,7 @@ export class Stream extends StreamRef { streamName: props.streamName, retentionPeriodHours, shardCount, - streamEncryption, - tags: props.tags + streamEncryption }); this.streamArn = this.stream.streamArn; this.streamName = this.stream.ref; diff --git a/packages/aws-cdk-kinesis/test/test.stream.ts b/packages/aws-cdk-kinesis/test/test.stream.ts index 9807b43d39aa7..778e8ee8c7940 100644 --- a/packages/aws-cdk-kinesis/test/test.stream.ts +++ b/packages/aws-cdk-kinesis/test/test.stream.ts @@ -90,36 +90,6 @@ export = { test.done(); }, - "attaches tags to stream"(test: Test) { - const stack = new Stack(); - - new Stream(stack, 'MyStream', { - tags: [{ - key: "key", - value: "value" - }] - }); - - expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "Tags": [ - { - "Key": "key", - "Value": "value" - } - ] - } - } - } - }); - - test.done(); - }, "auto-creates KMS key if encryption type is KMS but no key is provided"(test: Test) { const stack = new Stack(); From e981638ec932f77128d4900813d2ec01aca3e498 Mon Sep 17 00:00:00 2001 From: Sam Goodwin Date: Mon, 18 Jun 2018 00:39:34 -0700 Subject: [PATCH 3/3] Refactor for 0.7.1 --- .../kinesis}/.gitignore | 0 .../kinesis}/.npmignore | 0 .../kinesis}/README.md | 0 .../kinesis}/lib/index.ts | 0 .../kinesis}/lib/stream.ts | 8 ++++---- .../kinesis}/package.json | 20 +++++++++---------- .../kinesis}/test/test.stream.ts | 8 ++++---- packages/aws-cdk-all/package.json | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/.gitignore (100%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/.npmignore (100%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/README.md (100%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/lib/index.ts (100%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/lib/stream.ts (97%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/package.json (72%) rename packages/{aws-cdk-kinesis => @aws-cdk/kinesis}/test/test.stream.ts (99%) diff --git a/packages/aws-cdk-kinesis/.gitignore b/packages/@aws-cdk/kinesis/.gitignore similarity index 100% rename from packages/aws-cdk-kinesis/.gitignore rename to packages/@aws-cdk/kinesis/.gitignore diff --git a/packages/aws-cdk-kinesis/.npmignore b/packages/@aws-cdk/kinesis/.npmignore similarity index 100% rename from packages/aws-cdk-kinesis/.npmignore rename to packages/@aws-cdk/kinesis/.npmignore diff --git a/packages/aws-cdk-kinesis/README.md b/packages/@aws-cdk/kinesis/README.md similarity index 100% rename from packages/aws-cdk-kinesis/README.md rename to packages/@aws-cdk/kinesis/README.md diff --git a/packages/aws-cdk-kinesis/lib/index.ts b/packages/@aws-cdk/kinesis/lib/index.ts similarity index 100% rename from packages/aws-cdk-kinesis/lib/index.ts rename to packages/@aws-cdk/kinesis/lib/index.ts diff --git a/packages/aws-cdk-kinesis/lib/stream.ts b/packages/@aws-cdk/kinesis/lib/stream.ts similarity index 97% rename from packages/aws-cdk-kinesis/lib/stream.ts rename to packages/@aws-cdk/kinesis/lib/stream.ts index 42ad746dd0d19..7c7d498c86082 100644 --- a/packages/aws-cdk-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/kinesis/lib/stream.ts @@ -1,7 +1,7 @@ -import { Construct, Output, PolicyStatement, Token } from 'aws-cdk'; -import { IIdentityResource } from 'aws-cdk-iam'; -import * as kms from 'aws-cdk-kms'; -import { kinesis } from 'aws-cdk-resources'; +import { Construct, Output, PolicyStatement, Token } from '@aws-cdk/core'; +import { IIdentityResource } from '@aws-cdk/iam'; +import * as kms from '@aws-cdk/kms'; +import { kinesis } from '@aws-cdk/resources'; /** * A reference to a stream. The easiest way to instantiate is to call diff --git a/packages/aws-cdk-kinesis/package.json b/packages/@aws-cdk/kinesis/package.json similarity index 72% rename from packages/aws-cdk-kinesis/package.json rename to packages/@aws-cdk/kinesis/package.json index 47884f9ef5d75..8b938b8d947a6 100644 --- a/packages/aws-cdk-kinesis/package.json +++ b/packages/@aws-cdk/kinesis/package.json @@ -1,6 +1,6 @@ { - "name": "aws-cdk-kinesis", - "version": "0.6.0", + "name": "@aws-cdk/kinesis", + "version": "0.7.1", "description": "CDK Constructs for AWS Kinesis", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -33,16 +33,16 @@ "name": "Amazon Web Services", "url": "https://aws.amazon.com" }, - "license": "Apache-2.0", + "license": "LicenseRef-LICENSE", "devDependencies": { - "aws-cdk-assert": "^0.6.0", - "aws-cdk-toolkit": "^0.6.0", - "pkglint": "^0.6.0" + "@aws-cdk/assert": "^0.7.1", + "aws-cdk": "^0.7.1", + "pkglint": "^0.7.1" }, "dependencies": { - "aws-cdk": "^0.6.0", - "aws-cdk-iam": "^0.6.0", - "aws-cdk-kms": "^0.6.0", - "aws-cdk-resources": "^0.6.0" + "@aws-cdk/core": "^0.7.1", + "@aws-cdk/iam": "^0.7.1", + "@aws-cdk/kms": "^0.7.1", + "@aws-cdk/resources": "^0.7.1" } } diff --git a/packages/aws-cdk-kinesis/test/test.stream.ts b/packages/@aws-cdk/kinesis/test/test.stream.ts similarity index 99% rename from packages/aws-cdk-kinesis/test/test.stream.ts rename to packages/@aws-cdk/kinesis/test/test.stream.ts index 778e8ee8c7940..e7069d30e4bb0 100644 --- a/packages/aws-cdk-kinesis/test/test.stream.ts +++ b/packages/@aws-cdk/kinesis/test/test.stream.ts @@ -1,7 +1,7 @@ -import { Stack } from 'aws-cdk'; -import { expect } from 'aws-cdk-assert'; -import { User } from 'aws-cdk-iam'; -import { EncryptionKey } from 'aws-cdk-kms'; +import { expect } from '@aws-cdk/assert'; +import { Stack } from '@aws-cdk/core'; +import { User } from '@aws-cdk/iam'; +import { EncryptionKey } from '@aws-cdk/kms'; import { Test } from 'nodeunit'; import { Stream, StreamEncryption } from '../lib'; diff --git a/packages/aws-cdk-all/package.json b/packages/aws-cdk-all/package.json index 6d2778f6457f4..c3dd517628996 100644 --- a/packages/aws-cdk-all/package.json +++ b/packages/aws-cdk-all/package.json @@ -28,8 +28,8 @@ "@aws-cdk/ec2": "^0.7.1", "@aws-cdk/events": "^0.7.1", "@aws-cdk/iam": "^0.7.1", - "@aws-cdk/kms": "^0.7.1", "@aws-cdk/kinesis": "^0.7.1", + "@aws-cdk/kms": "^0.7.1", "@aws-cdk/lambda": "^0.7.1", "@aws-cdk/neptune": "^0.7.1", "@aws-cdk/quickstarts": "^0.7.1",