From edd53959af38969339205a5c33aaab11acc72fa6 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Wed, 27 Nov 2019 00:38:08 +0900 Subject: [PATCH] feat(sns): support KMS masterKey on SNS (#5052) Add Support KMS masterKey on SNS. It is allowed to set `masterKey` as `Kms::Key` to `TopicProps`. Fixes #1729 --- packages/@aws-cdk/aws-sns/lib/topic.ts | 9 ++++ packages/@aws-cdk/aws-sns/package.json | 3 ++ .../aws-sns/test/integ.sns.expected.json | 52 ++++++++++++++++++- packages/@aws-cdk/aws-sns/test/integ.sns.ts | 6 ++- packages/@aws-cdk/aws-sns/test/test.sns.ts | 16 ++++++ 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-sns/lib/topic.ts b/packages/@aws-cdk/aws-sns/lib/topic.ts index 1f9c1d38fee3c..e62c2c1468b28 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic.ts @@ -1,3 +1,4 @@ +import { IKey } from '@aws-cdk/aws-kms'; import { Construct, Stack } from '@aws-cdk/core'; import { CfnTopic } from './sns.generated'; import { ITopic, TopicBase } from './topic-base'; @@ -23,6 +24,13 @@ export interface TopicProps { * @default Generated name */ readonly topicName?: string; + + /** + * A KMS Key, either managed by this CDK app, or imported. + * + * @default None + */ + readonly masterKey?: IKey; } /** @@ -53,6 +61,7 @@ export class Topic extends TopicBase { const resource = new CfnTopic(this, 'Resource', { displayName: props.displayName, topicName: this.physicalName, + kmsMasterKeyId: props.masterKey && props.masterKey.keyId, }); this.topicArn = this.getResourceArnAttribute(resource.ref, { diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index a3ce20f01e8b8..12a74710bd1fe 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -76,6 +76,7 @@ "@aws-cdk/aws-cloudwatch": "1.18.0", "@aws-cdk/aws-events": "1.18.0", "@aws-cdk/aws-iam": "1.18.0", + "@aws-cdk/aws-kms": "1.18.0", "@aws-cdk/core": "1.18.0" }, "homepage": "https://github.com/aws/aws-cdk", @@ -83,7 +84,9 @@ "@aws-cdk/aws-cloudwatch": "1.18.0", "@aws-cdk/aws-events": "1.18.0", "@aws-cdk/aws-iam": "1.18.0", + "@aws-cdk/aws-kms": "1.18.0", "@aws-cdk/core": "1.18.0" + }, "engines": { "node": ">= 10.3.0" diff --git a/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json b/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json index 8e5512e49281d..ae421268bf6c2 100644 --- a/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json +++ b/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json @@ -4,8 +4,58 @@ "Type": "AWS::SNS::Topic", "Properties": { "DisplayName": "fooDisplayName", - "TopicName": "fooTopic" + "TopicName": "fooTopic", + "KmsMasterKeyId": { "Ref":"CustomKey1E6D0D07" } } + }, + "CustomKey1E6D0D07": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" } } } diff --git a/packages/@aws-cdk/aws-sns/test/integ.sns.ts b/packages/@aws-cdk/aws-sns/test/integ.sns.ts index c5bb1e5e991c4..7c744df2e3357 100644 --- a/packages/@aws-cdk/aws-sns/test/integ.sns.ts +++ b/packages/@aws-cdk/aws-sns/test/integ.sns.ts @@ -1,3 +1,4 @@ +import { Key } from '@aws-cdk/aws-kms'; import { App, Stack, StackProps } from '@aws-cdk/core'; import { Topic } from '../lib'; @@ -5,9 +6,12 @@ class SNSInteg extends Stack { constructor(scope: App, id: string, props?: StackProps) { super(scope, id, props); + const key = new Key(this, "CustomKey"); + new Topic(this, 'MyTopic', { topicName: 'fooTopic', - displayName: 'fooDisplayName' + displayName: 'fooDisplayName', + masterKey: key, }); } } diff --git a/packages/@aws-cdk/aws-sns/test/test.sns.ts b/packages/@aws-cdk/aws-sns/test/test.sns.ts index 099a2b2e472da..54beeb6d4be7b 100644 --- a/packages/@aws-cdk/aws-sns/test/test.sns.ts +++ b/packages/@aws-cdk/aws-sns/test/test.sns.ts @@ -1,5 +1,6 @@ import { expect, haveResource } from '@aws-cdk/assert'; import iam = require('@aws-cdk/aws-iam'); +import kms = require('@aws-cdk/aws-kms'); import cdk = require('@aws-cdk/core'); import { App, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -67,6 +68,21 @@ export = { test.done(); }, + 'specify kmsMasterKey'(test: Test) { + const stack = new cdk.Stack(); + const key = new kms.Key(stack, "CustomKey"); + + new sns.Topic(stack, 'MyTopic', { + masterKey: key, + }); + + expect(stack).to(haveResource("AWS::SNS::Topic", { + "KmsMasterKeyId": { "Ref": "CustomKey1E6D0D07" }, + })); + + test.done(); + }, + 'specify both'(test: Test) { const stack = new cdk.Stack();