diff --git a/packages/@aws-cdk/aws-sqs/lib/perms.ts b/packages/@aws-cdk/aws-sqs/lib/perms.ts deleted file mode 100644 index a9062475e14cc..0000000000000 --- a/packages/@aws-cdk/aws-sqs/lib/perms.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const QUEUE_GET_ACTIONS = [ - "sqs:ReceiveMessage", -]; - -export const QUEUE_CONSUME_ACTIONS = [ - "sqs:ChangeMessageVisibility", - "sqs:DeleteMessage", -]; - -export const QUEUE_PUT_ACTIONS = [ - "sqs:SendMessage", -]; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts index 55d591881e936..bd5c7c3acdae7 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts @@ -110,6 +110,88 @@ export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotif dependencies: [ this.policy! ] }; } + + /** + * Grant permissions to consume messages from a queue + * + * This will grant the following permissions: + * + * - sqs:ChangeMessageVisibility + * - sqs:ChangeMessageVisibilityBatch + * - sqs:DeleteMessage + * - sqs:ReceiveMessage + * - sqs:DeleteMessageBatch + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant consume rights to + */ + public grantConsumeMessages(identity?: iam.IPrincipal) { + this.grant(identity, + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:ChangeMessageVisibilityBatch', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:DeleteMessageBatch', + 'sqs:GetQueueAttributes'); + } + + /** + * Grant access to send messages to a queue to the given identity. + * + * This will grant the following permissions: + * + * - sqs:SendMessage + * - sqs:SendMessageBatch + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant send rights to + */ + public grantSendMessages(identity?: iam.IPrincipal) { + this.grant(identity, + 'sqs:SendMessage', + 'sqs:SendMessageBatch', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl'); + } + + /** + * Grant an IAM principal permissions to purge all messages from the queue. + * + * This will grant the following permissions: + * + * - sqs:PurgeQueue + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant send rights to + * @param queueActions additional queue actions to allow + */ + public grantPurge(identity?: iam.IPrincipal) { + this.grant(identity, + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl'); + } + + /** + * Grant the actions defined in queueActions to the identity Principal given + * on this SQS queue resource. + * + * @param identity Principal to grant right to + * @param queueActions The actions to grant + */ + public grant(identity?: iam.IPrincipal, ...queueActions: string[]) { + if (!identity) { + return; + } + + identity.addToPolicy(new iam.PolicyStatement() + .addResource(this.queueArn) + .addActions(...queueActions)); + } } /** diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index 9cea41ee1fc0b..ea6133ecbf754 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -1,7 +1,5 @@ -import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); import cdk = require('@aws-cdk/cdk'); -import perms = require('./perms'); import { QueueRef } from './queue-ref'; import { cloudformation } from './sqs.generated'; import { validateProps } from './validate-props'; @@ -277,64 +275,6 @@ export class Queue extends QueueRef { } } - /** - * Grant permissions to consume messages from a queue - * - * This will grant the following permissions: - * - * - sqs:ChangeMessageVisibility - * - sqs:DeleteMessage - * - sqs:ReceiveMessage - * - * @param identity Principal to grant consume rights to - */ - public grantConsumeMessages(identity?: iam.IPrincipal) { - this.grant(identity, perms.QUEUE_GET_ACTIONS.concat(perms.QUEUE_CONSUME_ACTIONS)); - } - - /** - * Grant access to receive messages from a queue to - * the given identity. - * - * This will grant sqs:ReceiveMessage - * - * @param identity Principal to grant receive rights to - */ - public grantReceiveMessages(identity?: iam.IPrincipal) { - this.grant(identity, perms.QUEUE_GET_ACTIONS); - } - - /** - * Grant access to send messages to a queue to the - * given identity. - * - * This will grant sqs:SendMessage - * - * @param identity Principal to grant send rights to - */ - public grantSendMessages(identity?: iam.IPrincipal) { - this.grant(identity, perms.QUEUE_PUT_ACTIONS); - } - - /** - * Grant the actions defined in queueActions - * to the identity Principal given. - * - * @param identity Principal to grant right to - * @param queueActions The actions to grant - */ - private grant(identity: iam.IPrincipal | undefined, - queueActions: string[]) { - - if (!identity) { - return; - } - - identity.addToPolicy(new iam.PolicyStatement() - .addResource(this.queueArn) - .addActions(...queueActions)); - } - /** * Look at the props, see if the FIFO props agree, and return the correct subset of props */ diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index 21f9529d14333..d6481db432925 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -1,10 +1,11 @@ import { expect, haveResource } from '@aws-cdk/assert'; -import { ArnPrincipal, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); import s3 = require('@aws-cdk/aws-s3'); import { resolve, Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import sqs = require('../lib'); +import { Queue } from '../lib'; // tslint:disable:object-literal-key-quotes @@ -56,7 +57,7 @@ export = { 'addToPolicy will automatically create a policy for this queue'(test: Test) { const stack = new Stack(); const queue = new sqs.Queue(stack, 'MyQueue'); - queue.addToResourcePolicy(new PolicyStatement().addAllResources().addActions('sqs:*').addPrincipal(new ArnPrincipal('arn'))); + queue.addToResourcePolicy(new iam.PolicyStatement().addAllResources().addActions('sqs:*').addPrincipal(new iam.ArnPrincipal('arn'))); expect(stack).toMatch({ "Resources": { "MyQueueE6CA6235": { @@ -113,92 +114,77 @@ export = { test.done(); }, - 'iam': { - 'grants permission to consume messages'(test: Test) { - const stack = new Stack(); - const role = new Role(stack, 'Role', { assumedBy: new ServicePrincipal('lambda.amazonaws.com') }); - const queue = new sqs.Queue(stack, 'Queue'); - queue.grantConsumeMessages(role); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "sqs:ReceiveMessage", - "sqs:ChangeMessageVisibility", - "sqs:DeleteMessage" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": - [ - "Queue4A7E3555", - "Arn" - ] - } - } - ] - } - })); - + 'grants': { + 'grantConsumeMessages'(test: Test) { + testGrant((q, p) => q.grantConsumeMessages(p), + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:ChangeMessageVisibilityBatch', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:DeleteMessageBatch', + 'sqs:GetQueueAttributes', + ); test.done(); }, - 'grants permission to receive messages'(test: Test) { - const stack = new Stack(); - const role = new Role(stack, 'Role', { assumedBy: new ServicePrincipal('lambda.amazonaws.com') }); - const queue = new sqs.Queue(stack, 'Queue'); - queue.grantReceiveMessages(role); + 'grantSendMessages'(test: Test) { + testGrant((q, p) => q.grantSendMessages(p), + 'sqs:SendMessage', + 'sqs:SendMessageBatch', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + test.done(); + }, - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "sqs:ReceiveMessage", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": - [ - "Queue4A7E3555", - "Arn" - ] - } - } - ] - } - })); + 'grantPurge'(test: Test) { + testGrant((q, p) => q.grantPurge(p), + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + test.done(); + }, + 'grant() is general purpose'(test: Test) { + testGrant((q, p) => q.grant(p, 'hello', 'world'), + 'hello', + 'world' + ); test.done(); }, - 'grants permission to send messages'(test: Test) { + 'grants also work on imported queues'(test: Test) { const stack = new Stack(); - const role = new Role(stack, 'Role', { assumedBy: new ServicePrincipal('lambda.amazonaws.com') }); - const queue = new sqs.Queue(stack, 'Queue'); - queue.grantSendMessages(role); + const queue = Queue.import(stack, 'Import', { + queueArn: 'imported-queue-arn', + queueUrl: 'https://queue-url' + }); + + const user = new iam.User(stack, 'User'); + + queue.grantPurge(user); expect(stack).to(haveResource('AWS::IAM::Policy', { "PolicyDocument": { "Statement": [ { - "Action": "sqs:SendMessage", + "Action": [ + "sqs:PurgeQueue", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], "Effect": "Allow", - "Resource": { - "Fn::GetAtt": - [ - "Queue4A7E3555", - "Arn" - ] - } + "Resource": "imported-queue-arn" } - ] + ], + "Version": "2012-10-17" } })); test.done(); } - }, 'queue encryption': { @@ -500,3 +486,29 @@ export = { } }; + +function testGrant(action: (q: Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { + const stack = new Stack(); + const queue = new Queue(stack, 'MyQueue'); + const principal = new iam.User(stack, 'User'); + + action(queue, principal); + + expect(stack).to(haveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": expectedActions, + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyQueueE6CA6235", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + } + })); +} \ No newline at end of file