diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.assets.json new file mode 100644 index 0000000000000..f032f0e4d5f5d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.assets.json @@ -0,0 +1,20 @@ +{ + "version": "40.0.0", + "files": { + "9f7857eee9ee57ddb56d90bf11818fd02733fd8755e480f17a77e9e5d8ad4f23": { + "source": { + "path": "LookupRoleStack.template.json", + "packaging": "file" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "9f7857eee9ee57ddb56d90bf11818fd02733fd8755e480f17a77e9e5d8ad4f23.json", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.template.json new file mode 100644 index 0000000000000..e3995d851df7c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/LookupRoleStack.template.json @@ -0,0 +1,62 @@ +{ + "Resources": { + "HelloPolicyD59007DF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ec2:*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Default", + "Roles": [ + "MyLookupTestRole" + ] + } + } + }, + "Outputs": { + "LookupRoleName": { + "Value": "MyLookupTestRole" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1e02a2deb191b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"40.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integ.json new file mode 100644 index 0000000000000..72979f85d97be --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "enableLookups": true, + "version": "40.0.0", + "testCases": { + "integ-iam-role-from-lookup/DefaultTest": { + "stacks": [ + "LookupRoleStack" + ], + "assertionStack": "integ-iam-role-from-lookup/DefaultTest/DeployAssert", + "assertionStackName": "integiamrolefromlookupDefaultTestDeployAssert63955306" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.assets.json new file mode 100644 index 0000000000000..ce9226d148771 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.assets.json @@ -0,0 +1,19 @@ +{ + "version": "40.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integiamrolefromlookupDefaultTestDeployAssert63955306.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/integiamrolefromlookupDefaultTestDeployAssert63955306.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/manifest.json new file mode 100644 index 0000000000000..0c5e5f7b8e35f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/manifest.json @@ -0,0 +1,180 @@ +{ + "version": "40.0.0", + "artifacts": { + "LookupRoleStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LookupRoleStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LookupRoleStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://12345678/test-region", + "properties": { + "templateFile": "LookupRoleStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/9f7857eee9ee57ddb56d90bf11818fd02733fd8755e480f17a77e9e5d8ad4f23.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "LookupRoleStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "LookupRoleStack.assets" + ], + "metadata": { + "/LookupRoleStack/MutableRoleLookupRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/LookupRoleStack/LookupRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/LookupRoleStack/HelloPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "policyName": "*" + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + } + ], + "/LookupRoleStack/HelloPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "HelloPolicyD59007DF" + } + ], + "/LookupRoleStack/LookupRoleName": [ + { + "type": "aws:cdk:logicalId", + "data": "LookupRoleName" + } + ], + "/LookupRoleStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LookupRoleStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LookupRoleStack" + }, + "integiamrolefromlookupDefaultTestDeployAssert63955306.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integiamrolefromlookupDefaultTestDeployAssert63955306.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integiamrolefromlookupDefaultTestDeployAssert63955306": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integiamrolefromlookupDefaultTestDeployAssert63955306.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integiamrolefromlookupDefaultTestDeployAssert63955306.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integiamrolefromlookupDefaultTestDeployAssert63955306.assets" + ], + "metadata": { + "/integ-iam-role-from-lookup/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-iam-role-from-lookup/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-iam-role-from-lookup/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "missing": [ + { + "key": "cc-api-provider:account=12345678:exactIdentifier=MyLookupTestRole:propertiesToReturn.0=Arn:region=test-region:typeName=AWS$:$:IAM$:$:Role", + "provider": "cc-api-provider", + "props": { + "dummyValue": [ + { + "Arn": "arn:${Token[AWS.Partition.7]}:iam::123456789012:role/DUMMY_ARN" + } + ], + "account": "12345678", + "region": "test-region", + "typeName": "AWS::IAM::Role", + "exactIdentifier": "MyLookupTestRole", + "propertiesToReturn": [ + "Arn" + ], + "lookupRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region" + } + } + ] +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/tree.json new file mode 100644 index 0000000000000..2b7aab73f45ba --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.js.snapshot/tree.json @@ -0,0 +1,184 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "LookupRoleStack": { + "id": "LookupRoleStack", + "path": "LookupRoleStack", + "children": { + "MutableRoleLookupRole": { + "id": "MutableRoleLookupRole", + "path": "LookupRoleStack/MutableRoleLookupRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0", + "metadata": [ + "*" + ] + } + }, + "LookupRole": { + "id": "LookupRole", + "path": "LookupRoleStack/LookupRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0", + "metadata": [ + "*", + "*" + ] + } + }, + "HelloPolicy": { + "id": "HelloPolicy", + "path": "LookupRoleStack/HelloPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LookupRoleStack/HelloPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "ec2:*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "policyName": "Default", + "roles": [ + "MyLookupTestRole" + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0", + "metadata": [ + { + "policyName": "*" + }, + { + "addStatements": [ + {} + ] + }, + { + "attachToRole": [ + "*" + ] + } + ] + } + }, + "LookupRoleName": { + "id": "LookupRoleName", + "path": "LookupRoleStack/LookupRoleName", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "LookupRoleStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "LookupRoleStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "integ-iam-role-from-lookup": { + "id": "integ-iam-role-from-lookup", + "path": "integ-iam-role-from-lookup", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-iam-role-from-lookup/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-iam-role-from-lookup/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-iam-role-from-lookup/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-iam-role-from-lookup/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-iam-role-from-lookup/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.ts new file mode 100644 index 0000000000000..9d5f8c6690047 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.role-from-lookup.ts @@ -0,0 +1,36 @@ +import { App, CfnOutput, Stack } from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { Policy, PolicyStatement, Role } from 'aws-cdk-lib/aws-iam'; + +/* + * To run this integ test, create an IAM Role with the name `MyLookupTestRole` in your AWS account beforehand. + * + * ```bash + * aws iam create-role --role-name MyLookupTestRole --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"sqs.amazonaws.com"},"Action":"sts:AssumeRole"}]}' + * ``` + */ +const roleName = 'MyLookupTestRole'; + +const app = new App(); + +const stack = new Stack(app, 'LookupRoleStack', { + env: { + account: process.env.CDK_INTEG_ACCOUNT ?? process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_INTEG_REGION ?? process.env.CDK_DEFAULT_REGION, + }, +}); + +const lookupRole = Role.fromLookup(stack, 'LookupRole', { + roleName, +}); + +const policy = new Policy(stack, 'HelloPolicy', { policyName: 'Default' }); +policy.addStatements(new PolicyStatement({ actions: ['ec2:*'], resources: ['*'] })); +policy.attachToRole(lookupRole); + +new CfnOutput(stack, 'LookupRoleName', { value: lookupRole.roleName }); + +new IntegTest(app, 'integ-iam-role-from-lookup', { + enableLookups: true, + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-iam/README.md b/packages/aws-cdk-lib/aws-iam/README.md index 2da42c6819e09..b89c9bd4a8d86 100644 --- a/packages/aws-cdk-lib/aws-iam/README.md +++ b/packages/aws-cdk-lib/aws-iam/README.md @@ -125,6 +125,14 @@ const role = iam.Role.fromRoleArn(this, 'Role', 'arn:aws:iam::123456789012:role/ }); ``` +If you want to lookup roles that actually exist in your account, you can use `Role.fromLookup()`. + +```ts +const role = iam.Role.fromLookup(this, 'Role', { + roleName: 'MyExistingRole', +}); +``` + ### Customizing role creation It is best practice to allow CDK to manage IAM roles and permissions. You can prevent CDK from diff --git a/packages/aws-cdk-lib/aws-iam/lib/role.ts b/packages/aws-cdk-lib/aws-iam/lib/role.ts index e625145279436..8794dcccf985c 100644 --- a/packages/aws-cdk-lib/aws-iam/lib/role.ts +++ b/packages/aws-cdk-lib/aws-iam/lib/role.ts @@ -13,7 +13,8 @@ import { ImportedRole } from './private/imported-role'; import { MutatingPolicyDocumentAdapter } from './private/policydoc-adapter'; import { PrecreatedRole } from './private/precreated-role'; import { AttachedPolicies, UniqueStringSet } from './private/util'; -import { ArnFormat, Duration, Resource, Stack, Token, TokenComparison, Aspects, Annotations, RemovalPolicy, AspectPriority } from '../../core'; +import * as cxschema from '../../cloud-assembly-schema'; +import { ArnFormat, Duration, Resource, Stack, Token, TokenComparison, Aspects, Annotations, RemovalPolicy, AspectPriority, ContextProvider } from '../../core'; import { getCustomizeRolesConfig, getPrecreatedRoleConfig, CUSTOMIZE_ROLES_CONTEXT_KEY, CustomizeRoleConfig } from '../../core/lib/helpers-internal'; import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource'; @@ -229,6 +230,21 @@ export interface CustomizeRolesOptions { */ export interface FromRoleNameOptions extends FromRoleArnOptions { } +/** + * Properties for looking up an existing Role. + */ +export interface RoleLookupOptions extends FromRoleArnOptions { + /** + * The name of the role to lookup. + * + * If the role you want to lookup is a service role, you need to specify + * the role name without the 'service-role' prefix. For example, if the role arn is + * 'arn:aws:iam::123456789012:role/service-role/ExampleServiceExecutionRole', + * you need to specify the role name as 'ExampleServiceExecutionRole'. + */ + readonly roleName: string; +} + /** * IAM Role * @@ -236,6 +252,37 @@ export interface FromRoleNameOptions extends FromRoleArnOptions { } * the specified AWS service principal defined in `serviceAssumeRole`. */ export class Role extends Resource implements IRole { + /** + * Lookup an existing Role. + */ + public static fromLookup(scope: Construct, id: string, options: RoleLookupOptions): IRole { + if (Token.isUnresolved(options.roleName)) { + throw new Error('All arguments to look up a role must be concrete (no Tokens)'); + } + + const response: {[key: string]: any}[] = ContextProvider.getValue(scope, { + provider: cxschema.ContextProvider.CC_API_PROVIDER, + props: { + typeName: 'AWS::IAM::Role', + exactIdentifier: options.roleName, + propertiesToReturn: [ + 'Arn', + ], + } as cxschema.CcApiContextQuery, + dummyValue: [ + { + // eslint-disable-next-line @cdklabs/no-literal-partition + Arn: 'arn:aws:iam::123456789012:role/DUMMY_ARN', + }, + ], + }).value; + + // getValue returns a list of result objects. We are expecting 1 result or Error. + const role = response[0]; + + return this.fromRoleArn(scope, id, role.Arn, options); + } + /** * Import an external role by ARN. * diff --git a/packages/aws-cdk-lib/aws-iam/test/role.from-lookup.test.ts b/packages/aws-cdk-lib/aws-iam/test/role.from-lookup.test.ts new file mode 100644 index 0000000000000..cc718c15b2c4e --- /dev/null +++ b/packages/aws-cdk-lib/aws-iam/test/role.from-lookup.test.ts @@ -0,0 +1,60 @@ +import * as cxschema from '../../cloud-assembly-schema'; +import { CfnParameter, ContextProvider, Stack, Token } from '../../core'; +import * as iam from '../lib'; + +/* eslint-disable */ +describe('Role from lookup', () => { + test('return correct role info', () => { + // GIVEN + const resultObjs = [ + { + 'Arn': 'arn:aws:iam::123456789012:role/MyExistingRole', + }, + ]; + const value = { + value: resultObjs, + }; + const mock = jest.spyOn(ContextProvider, 'getValue').mockReturnValue(value); + + // WHEN + const stack = new Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const role = iam.Role.fromLookup(stack, 'MyRole', { + roleName: 'MyExistingRole', + }); + + // THEN + expect(role.roleArn).toEqual('arn:aws:iam::123456789012:role/MyExistingRole'); + + expect(mock).toHaveBeenCalledWith(stack, { + provider: cxschema.ContextProvider.CC_API_PROVIDER, + props: { + typeName: 'AWS::IAM::Role', + exactIdentifier: 'MyExistingRole', + propertiesToReturn: [ + 'Arn', + ], + } as cxschema.CcApiContextQuery, + dummyValue: [ + { + 'Arn': 'arn:aws:iam::123456789012:role/DUMMY_ARN', + }, + ], + }); + + mock.mockRestore(); + }); + + test('throw error if role name is a token', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const param = new CfnParameter(stack, 'MyParam', { + type: 'String', + default: 'MyExistingRole', + }); + + expect(() => iam.Role.fromLookup(stack, 'MyRole', { + roleName: param.valueAsString, + })).toThrow(/All arguments to look up a role must be concrete \(no Tokens\)/); + }); +}); +/* eslint-enable */