From f308485dd32538d6d01e625715c018e769b5caf5 Mon Sep 17 00:00:00 2001 From: Elliot Murphy Date: Thu, 15 Aug 2019 12:28:28 -0400 Subject: [PATCH] fix(iam): support NotActions/NotResources (#964) Signed-off-by: Elliot Murphy --- .../@aws-cdk/aws-iam/lib/policy-statement.ts | 30 ++++++++++++++++++- .../aws-iam/test/test.policy-document.ts | 11 +++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts index 4f29df14dc6ab..63c8c2396e494 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts @@ -14,16 +14,20 @@ export class PolicyStatement { public effect: Effect; private action = new Array(); + private notaction = new Array(); private principal: { [key: string]: any[] } = {}; private resource = new Array(); + private notresource = new Array(); private condition: { [key: string]: any } = { }; constructor(props: PolicyStatementProps = {}) { this.effect = props.effect || Effect.ALLOW; this.addActions(...props.actions || []); + this.addNotActions(...props.notactions || []); this.addPrincipals(...props.principals || []); this.addResources(...props.resources || []); + this.addNotResources(...props.notresources || []); if (props.conditions !== undefined) { this.addConditions(props.conditions); } @@ -37,6 +41,10 @@ export class PolicyStatement { this.action.push(...actions); } + public addNotActions(...notactions: string[]) { + this.notaction.push(...notactions); + } + // // Principal // @@ -98,6 +106,10 @@ export class PolicyStatement { this.resource.push(...arns); } + public addNotResources(...arns: string[]) { + this.notresource.push(...arns); + } + /** * Adds a ``"*"`` resource to this statement. */ @@ -142,10 +154,12 @@ export class PolicyStatement { public toStatementJson(): any { return noUndef({ Action: _norm(this.action), + NotAction: _norm(this.notaction), Condition: _norm(this.condition), Effect: _norm(this.effect), Principal: _normPrincipal(this.principal), Resource: _norm(this.resource), + NotResource: _norm(this.notresource), Sid: _norm(this.sid), }); @@ -229,6 +243,13 @@ export interface PolicyStatementProps { */ readonly actions?: string[]; + /** + * List of not actions to add to the statement + * + * @default - no actions + */ + readonly notactions?: string[]; + /** * List of principals to add to the statement * @@ -239,10 +260,17 @@ export interface PolicyStatementProps { /** * Resource ARNs to add to the statement * - * @default - no principals + * @default - no resources */ readonly resources?: string[]; + /** + * NotResource ARNs to add to the statement + * + * @default - no resources + */ + readonly notresources?: string[]; + /** * Conditions to add to the statement * diff --git a/packages/@aws-cdk/aws-iam/test/test.policy-document.ts b/packages/@aws-cdk/aws-iam/test/test.policy-document.ts index 695d06f053ada..f61fdb680e4a8 100644 --- a/packages/@aws-cdk/aws-iam/test/test.policy-document.ts +++ b/packages/@aws-cdk/aws-iam/test/test.policy-document.ts @@ -43,19 +43,26 @@ export = { const p1 = new PolicyStatement(); p1.addActions('sqs:SendMessage'); p1.addResources('*'); + p1.addNotResources('arn:aws:sqs:us-east-1:123456789012:forbidden_queue'); const p2 = new PolicyStatement(); p2.effect = Effect.DENY; p2.addActions('cloudformation:CreateStack'); + const p3 = new PolicyStatement(); + p3.effect = Effect.ALLOW; + p3.addNotActions('cloudformation:UpdateTerminationProtection'); + doc.addStatements(p1); doc.addStatements(p2); + doc.addStatements(p3); test.deepEqual(stack.resolve(doc), { Version: '2012-10-17', Statement: - [ { Effect: 'Allow', Action: 'sqs:SendMessage', Resource: '*' }, - { Effect: 'Deny', Action: 'cloudformation:CreateStack' } ] }); + [{ Effect: 'Allow', Action: 'sqs:SendMessage', Resource: '*', NotResource: 'arn:aws:sqs:us-east-1:123456789012:forbidden_queue' }, + { Effect: 'Deny', Action: 'cloudformation:CreateStack' }, + { Effect: 'Allow', NotAction: 'cloudformation:UpdateTerminationProtection' } ] }); test.done(); },