From a283a392ac5c9035c5d38a7e40c21bb8131f5692 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 13 Aug 2018 12:25:32 +0300 Subject: [PATCH] feat(aws-iam): support maxSessionDuration for Role (#545) Allow specifying a maximum session duration for roles. Fixes #543 --- packages/@aws-cdk/aws-iam/lib/role.ts | 34 ++++++++++++ packages/@aws-cdk/aws-iam/test/test.role.ts | 59 +++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 4d4d079febf00..260f99f02bb60 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -41,6 +41,27 @@ export interface RoleProps { * Acknowledging IAM Resources in AWS CloudFormation Templates. */ roleName?: string; + + /** + * The maximum session duration (in seconds) that you want to set for the + * specified role. If you do not specify a value for this setting, the + * default maximum of one hour is applied. This setting can have a value + * from 1 hour (3600sec) to 12 (43200sec) hours. + * + * Anyone who assumes the role from the AWS CLI or API can use the + * DurationSeconds API parameter or the duration-seconds CLI parameter to + * request a longer session. The MaxSessionDuration setting determines the + * maximum duration that can be requested using the DurationSeconds + * parameter. + * + * If users don't specify a value for the DurationSeconds parameter, their + * security credentials are valid for one hour by default. This applies when + * you use the AssumeRole* API operations or the assume-role* CLI operations + * but does not apply when you use those operations to create a console URL. + * + * @link https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html + */ + maxSessionDurationSec?: number; } /** @@ -85,11 +106,14 @@ export class Role extends Construct implements IIdentityResource, IPrincipal, ID this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy); this.managedPolicies = props.managedPolicyArns || [ ]; + validateMaxSessionDuration(props.maxSessionDurationSec); + const role = new cloudformation.RoleResource(this, 'Resource', { assumeRolePolicyDocument: this.assumeRolePolicy as any, managedPolicyArns: undefinedIfEmpty(() => this.managedPolicies), path: props.path, roleName: props.roleName, + maxSessionDuration: props.maxSessionDurationSec }); this.roleArn = role.roleArn; @@ -140,3 +164,13 @@ function createAssumeRolePolicy(principal: PolicyPrincipal) { .addPrincipal(principal) .addAction(principal.assumeRoleAction)); } + +function validateMaxSessionDuration(duration?: number) { + if (duration === undefined) { + return; + } + + if (duration < 3600 || duration > 43200) { + throw new Error(`maxSessionDuration is set to ${duration}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/test/test.role.ts b/packages/@aws-cdk/aws-iam/test/test.role.ts index dfdef1d78f97c..98876bdf8d2a2 100644 --- a/packages/@aws-cdk/aws-iam/test/test.role.ts +++ b/packages/@aws-cdk/aws-iam/test/test.role.ts @@ -117,5 +117,64 @@ export = { })); test.done(); + }, + + 'maxSessionDuration': { + + 'is not specified by default'(test: Test) { + const stack = new Stack(); + new Role(stack, 'MyRole', { assumedBy: new ServicePrincipal('sns.amazonaws.com') }); + expect(stack).toMatch({ + Resources: { + MyRoleF48FFE04: { + Type: "AWS::IAM::Role", + Properties: { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: "sts:AssumeRole", + Effect: "Allow", + Principal: { + Service: "sns.amazonaws.com" + } + } + ], + Version: "2012-10-17" + } + } + } + } + }); + test.done(); + }, + + 'can be used to specify the maximum session duration for assuming the role'(test: Test) { + const stack = new Stack(); + + new Role(stack, 'MyRole', { maxSessionDurationSec: 3700, assumedBy: new ServicePrincipal('sns.amazonaws.com') }); + + expect(stack).to(haveResource('AWS::IAM::Role', { + MaxSessionDuration: 3700 + })); + + test.done(); + }, + + 'must be between 3600 and 43200'(test: Test) { + const stack = new Stack(); + + const assumedBy = new ServicePrincipal('bla'); + + new Role(stack, 'MyRole1', { assumedBy, maxSessionDurationSec: 3600 }); + new Role(stack, 'MyRole2', { assumedBy, maxSessionDurationSec: 43200 }); + + const expected = (val: any) => `maxSessionDuration is set to ${val}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`; + test.throws(() => new Role(stack, 'MyRole3', { assumedBy, maxSessionDurationSec: 60 }), expected(60)); + test.throws(() => new Role(stack, 'MyRole4', { assumedBy, maxSessionDurationSec: 3599 }), expected(3599)); + test.throws(() => new Role(stack, 'MyRole5', { assumedBy, maxSessionDurationSec: 43201 }), expected(43201)); + + test.done(); + } } + };