Skip to content

Commit

Permalink
feat(iam): support permissions boundary policy for User and Role (aws…
Browse files Browse the repository at this point in the history
…#3584)

* Add permissions boundary to IAM user and role L2 constructs

* fix copy/paste typo

* remove unnecessary quotes
  • Loading branch information
Sander Knape authored and mergify[bot] committed Aug 9, 2019
1 parent ac77990 commit 661a95e
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
23 changes: 22 additions & 1 deletion packages/@aws-cdk/aws-iam/lib/role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ export interface RoleProps {
*/
readonly path?: string;

/**
* AWS supports permissions boundaries for IAM entities (users or roles).
* A permissions boundary is an advanced feature for using a managed policy
* to set the maximum permissions that an identity-based policy can grant to
* an IAM entity. An entity's permissions boundary allows it to perform only
* the actions that are allowed by both its identity-based policies and its
* permissions boundaries.
*
* @link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary
* @link https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html
*
* @default - No permissions boundary.
*/
readonly permissionsBoundary?: IManagedPolicy;

/**
* A name for the IAM role. For valid values, see the RoleName parameter for
* the CreateRole action in the IAM API Reference.
Expand Down Expand Up @@ -196,6 +211,11 @@ export class Role extends Resource implements IRole {
*/
public readonly policyFragment: PrincipalPolicyFragment;

/**
* Returns the permissions boundary attached to this role
*/
public readonly permissionsBoundary?: IManagedPolicy;

private defaultPolicy?: Policy;
private readonly managedPolicies: IManagedPolicy[] = [];
private readonly attachedPolicies = new AttachedPolicies();
Expand All @@ -207,7 +227,7 @@ export class Role extends Resource implements IRole {

this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, props.externalId);
this.managedPolicies.push(...props.managedPolicies || []);

this.permissionsBoundary = props.permissionsBoundary;
const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds();
validateMaxSessionDuration(maxSessionDuration);

Expand All @@ -216,6 +236,7 @@ export class Role extends Resource implements IRole {
managedPolicyArns: Lazy.listValue({ produce: () => this.managedPolicies.map(p => p.managedPolicyArn) }, { omitEmpty: true }),
policies: _flatten(props.inlinePolicies),
path: props.path,
permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
roleName: this.physicalName,
maxSessionDuration,
});
Expand Down
22 changes: 22 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ export interface UserProps {
*/
readonly path?: string;

/**
* AWS supports permissions boundaries for IAM entities (users or roles).
* A permissions boundary is an advanced feature for using a managed policy
* to set the maximum permissions that an identity-based policy can grant to
* an IAM entity. An entity's permissions boundary allows it to perform only
* the actions that are allowed by both its identity-based policies and its
* permissions boundaries.
*
* @link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-permissionsboundary
* @link https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html
*
* @default - No permissions boundary.
*/
readonly permissionsBoundary?: IManagedPolicy;

/**
* A name for the IAM user. For valid values, see the UserName parameter for
* the CreateUser action in the IAM API Reference. If you don't specify a
Expand Down Expand Up @@ -98,6 +113,11 @@ export class User extends Resource implements IIdentity {
*/
public readonly userArn: string;

/**
* Returns the permissions boundary attached to this user
*/
public readonly permissionsBoundary?: IManagedPolicy;

public readonly policyFragment: PrincipalPolicyFragment;

private readonly groups = new Array<any>();
Expand All @@ -111,12 +131,14 @@ export class User extends Resource implements IIdentity {
});

this.managedPolicies.push(...props.managedPolicies || []);
this.permissionsBoundary = props.permissionsBoundary;

const user = new CfnUser(this, 'Resource', {
userName: this.physicalName,
groups: undefinedIfEmpty(() => this.groups),
managedPolicyArns: Lazy.listValue({ produce: () => this.managedPolicies.map(p => p.managedPolicyArn) }, { omitEmpty: true }),
path: props.path,
permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
loginProfile: this.parseLoginProfile(props)
});

Expand Down
30 changes: 29 additions & 1 deletion packages/@aws-cdk/aws-iam/test/test.role.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert';
import { Duration, Stack } from '@aws-cdk/core';
import { Test } from 'nodeunit';
import { ArnPrincipal, CompositePrincipal, FederatedPrincipal, PolicyStatement, Role, ServicePrincipal, User } from '../lib';
import { ArnPrincipal, CompositePrincipal, FederatedPrincipal, ManagedPolicy, PolicyStatement, Role, ServicePrincipal, User } from '../lib';

export = {
'default role'(test: Test) {
Expand Down Expand Up @@ -290,4 +290,32 @@ export = {
test.done();
},

'can supply permissions boundary managed policy'(test: Test) {
// GIVEN
const stack = new Stack();

const permissionsBoundary = ManagedPolicy.fromAwsManagedPolicyName('managed-policy');

new Role(stack, 'MyRole', {
assumedBy: new ServicePrincipal('sns.amazonaws.com'),
permissionsBoundary,
});

expect(stack).to(haveResource('AWS::IAM::Role', {
PermissionsBoundary: {
"Fn::Join": [
"",
[
"arn:",
{
Ref: "AWS::Partition"
},
":iam::aws:policy/managed-policy"
]
]
}
}));

test.done();
}
};
28 changes: 28 additions & 0 deletions packages/@aws-cdk/aws-iam/test/test.user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,34 @@ export = {
]
}));

test.done();
},

'can supply permissions boundary managed policy'(test: Test) {
// GIVEN
const stack = new Stack();

const permissionsBoundary = ManagedPolicy.fromAwsManagedPolicyName('managed-policy');

new User(stack, 'MyUser', {
permissionsBoundary,
});

expect(stack).to(haveResource('AWS::IAM::User', {
PermissionsBoundary: {
"Fn::Join": [
"",
[
"arn:",
{
Ref: "AWS::Partition"
},
":iam::aws:policy/managed-policy"
]
]
}
}));

test.done();
}
};

0 comments on commit 661a95e

Please sign in to comment.