diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 88ee7151c1f6e..f2eef64775ccf 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -155,7 +155,12 @@ export class Role extends Resource implements IRole { public static fromRoleArn(scope: Construct, id: string, roleArn: string, options: FromRoleArnOptions = {}): IRole { const scopeStack = Stack.of(scope); const parsedArn = scopeStack.parseArn(roleArn); - const roleName = parsedArn.resourceName!; + const resourceName = parsedArn.resourceName!; + // service roles have an ARN like 'arn:aws:iam:::role/service-role/' + // we want to support these as well, so strip out the 'service-role/' prefix if we see it + const roleName = resourceName.startsWith('service-role/') + ? resourceName.slice('service-role/'.length) + : resourceName; abstract class Import extends Resource implements IRole { public readonly grantPrincipal: IPrincipal = this; diff --git a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts index 759d6bd98fe4a..ffd29715c14f6 100644 --- a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts @@ -476,6 +476,27 @@ describe('IAM Role.fromRoleArn', () => { }); }); }); + + describe('imported with the ARN of a service role', () => { + beforeEach(() => { + roleStack = new Stack(); + importedRole = Role.fromRoleArn(roleStack, 'Role', + `arn:aws:iam::${roleAccount}:role/service-role/codebuild-role`); + }); + + it("correctly strips the 'service-role' prefix from the role name", () => { + new Policy(roleStack, 'Policy', { + statements: [somePolicyStatement()], + roles: [importedRole], + }); + + expect(roleStack).toHaveResourceLike('AWS::IAM::Policy', { + "Roles": [ + "codebuild-role", + ], + }); + }); + }); }); function somePolicyStatement() {