Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(kinesis): stream encryption with the Kinesis master key #7057

Merged
merged 7 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions packages/@aws-cdk/aws-kinesis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ Streams are not encrypted by default.
[Stream encryption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) enables
server-side encryption using an AWS KMS key for a specified stream.

You can enable encryption on your streams by specifying the `encryption` property. A KMS key will be created for you and associated with the stream.
You can enable encryption on your stream with the master key owned by Kinesis Data Streams by specifying the `encryption` property.

```ts
const stream = new Stream(this, "MyEncryptedStream", {
new Stream(this, 'MyEncryptedStream', {
encryption: StreamEncryption.MANAGED
});
```

You can enable encryption on your stream with a user-managed key by specifying the `encryption` property.
A KMS key will be created for you and associated with the stream.

```ts
new Stream(this, "MyEncryptedStream", {
encryption: StreamEncryption.KMS
});
```
Expand All @@ -74,7 +83,7 @@ import * as kms from "@aws-cdk/aws-kms";

const key = new kms.Key(this, "MyKey");

const stream = new Stream(this, "MyEncryptedStream", {
new Stream(this, "MyEncryptedStream", {
encryption: StreamEncryption.KMS,
encryptionKey: key
});
Expand Down
22 changes: 18 additions & 4 deletions packages/@aws-cdk/aws-kinesis/lib/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export interface StreamProps {
* 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
* @default - StreamEncryption.KMS if encryptionKey is specified, or StreamEncryption.UNENCRYPTED otherwise
*/
readonly encryption?: StreamEncryption;

Expand All @@ -210,7 +210,7 @@ export interface StreamProps {
*
* The 'encryption' property must be set to "Kms".
*
* @default If encryption is set to "Kms" and this property is undefined, a
* @default - If encryption is set to "KMS" and this property is undefined, a
* new KMS key will be created and associated with this stream.
*/
readonly encryptionKey?: kms.IKey;
Expand Down Expand Up @@ -294,8 +294,9 @@ export class Stream extends StreamBase {
encryptionKey?: kms.IKey
} {

// default to unencrypted.
const encryptionType = props.encryption || StreamEncryption.UNENCRYPTED;
// default based on whether encryption key is specified
const encryptionType = props.encryption ??
(props.encryptionKey ? StreamEncryption.KMS : StreamEncryption.UNENCRYPTED);

// if encryption key is set, encryption must be set to KMS.
if (encryptionType !== StreamEncryption.KMS && props.encryptionKey) {
Expand All @@ -306,6 +307,14 @@ export class Stream extends StreamBase {
return { streamEncryption: undefined, encryptionKey: undefined };
}

if (encryptionType === StreamEncryption.MANAGED) {
const encryption = { encryptionType: 'KMS', keyId: 'alias/aws/kinesis'};
return {
streamEncryption: encryption,
encryptionKey: undefined
};
}

if (encryptionType === StreamEncryption.KMS) {
const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', {
description: `Created by ${this.node.path}`
Expand Down Expand Up @@ -336,4 +345,9 @@ export enum StreamEncryption {
* If `encryptionKey` is specified, this key will be used, otherwise, one will be defined.
*/
KMS = 'KMS',

/**
* Server-side encryption with a master key managed by Amazon Kinesis
*/
MANAGED = 'MANAGED'
}
58 changes: 57 additions & 1 deletion packages/@aws-cdk/aws-kinesis/test/test.stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect } from '@aws-cdk/assert';
import { expect, haveResource } from '@aws-cdk/assert';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import { App, Duration, Stack } from '@aws-cdk/core';
Expand Down Expand Up @@ -97,6 +97,62 @@ export = {

test.done();
},

'uses Kinesis master key if MANAGED encryption type is provided'(test: Test) {
// GIVEN
const stack = new Stack();

// WHEN
new Stream(stack, 'MyStream', {
encryption: StreamEncryption.MANAGED
});

// THEN
expect(stack).toMatch({
"Resources": {
"MyStream5C050E93": {
"Type": "AWS::Kinesis::Stream",
"Properties": {
"ShardCount": 1,
"RetentionPeriodHours": 24,
"StreamEncryption": {
"EncryptionType": "KMS",
"KeyId": "alias/aws/kinesis"
}
}
}
}
});

test.done();
},

'if a KMS key is supplied, use KMS as the encryption type'(test: Test) {
// GIVEN
const stack = new Stack();
const key = new kms.Key(stack, 'myKey');

// WHEN
new Stream(stack, 'myStream', {
encryptionKey: key
});

// THEN
expect(stack).to(haveResource('AWS::Kinesis::Stream', {
ShardCount: 1,
RetentionPeriodHours: 24,
StreamEncryption: {
EncryptionType: 'KMS',
KeyId: {
'Fn::GetAtt': ['myKey441A1E73', 'Arn']
}
}
})
);

test.done();
},

"auto-creates KMS key if encryption type is KMS but no key is provided"(test: Test) {
const stack = new Stack();

Expand Down