aws-cdk
aws-cdk copied to clipboard
Role.addManagedPolicy does not work for imported roles
Inconsistent Behavior: aws_iam.Role.attachManagedPolicy vs aws_iam.ManagedPolicy.attachToRole
The Scenario
TLDR; aws_iam.Role.attachManagedPolicy does not attach the specified managed policy to the role, aws_iam.ManagedPolicy.attachToRole does.
I have two stacks: one stack deploys roles another deploys an application stack (both are in the same account). The roles stack is deployed first.
In the application stack, I would like to attach a managed policy to a role in the first.
Attempting to use aws_iam.Role.attachManagedPolicy does not create the association but aws_iam.ManagedPolicy.attachToRole does.
Environment
- CDK CLI Version: 1.39.0 (build 5d727c1)
- Module Version: 1.38.0
- Node.js Version: v14.0.0
- OS: macOS Mojave 10.14.6 (18G4032)
- Language: Typescript and Python
Other information
Steps to reproduce
- Deploy one stack with an IAM role
- In a second stack create a managed policy
- In the second stack Import the role using aws_iam.Role.fromRoleArn (importedRole)
- In the second stack attempt to add the managed policy to importedRole via importedRole.attachManagedPolicy
Observed
- cdk synth does not show any associations made between the role and the managed policy
- using ManagedPolicy.attachToRole works however
Expected
- cdk synth (and subsequently) cdk deploy should associate the role and managed policy when Role.attachManagedPolicy is used
It looks like addManagedPolicy is not implemented... https://github.com/aws/aws-cdk/blob/v1.42.1/packages/@aws-cdk/aws-iam/lib/role.ts#L216
Is there a way that this can be clearly stated in documentation?
We can certainly add that to the documentation.
Could this be resolved by changing addManagedPolicy to take a ManagedPolicy instead of IManagedPolicy as its argument (and then calling the appropriate method on the managed policy to attach it to the role)?
I feel like this could fit in with the design guidelines - "It's okay to enable multiple ways to achieve the same thing, in order to make it more natural for users who come from different mental models", even though it technically violates [awslint:ref-via-interface]. Also the attachInlinePolicy method on imported roles requires a Policy (opposed to an IPolicy), so this wouldn't be especially out of place.
Just run into this bug, trying to configure some policies for roles managed outside of cdk app 😢
Same here, this is really unfortunate. It fails silently and doesn't attach anything. I guess I'll be forced to create a proper inline policy and do the right thing following the principle of least privilege.
We just hit this issue. Especially surprising that even a warning is not getting printed. https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/aws-iam/lib/role.ts#L227
The workaround I found is below. It's not perfect, but it's pretty good:
- define the policy statement(s)
- create the managed policy with that policy statement
- attach the policy statement to the imported role.
Example
const statement = new PolicyStatement({
effect: Effect.ALLOW,
actions: ['execute-api:Invoke'],
resources: [
//SOME RESOURCE
]
})
this.cloudAuthAccessPolicy = new ManagedPolicy(this, 'FOO', {
managedPolicyName: 'FOO',
description: "BAR",
statements: [
statement
]
})
const role = Role.fromRoleArn(this, `name`, `arn:aws:iam::${props.account}:role/SOME_ROLE_NAME`)
role.addToPolicy(statement)
I know this issue has been open for some time now. Is there a fix team is working on ?. I have a use case where I want to create roles and policies separately and then associate them later using Role.addManagedPolicy.
The only way right now is to attach the policy to the role to policy during the role creation itself (using managed_policies) which is not ideal.
This is still wrong in the documentation when importing an existing role.
One can set a mutable option when importing the role (by default it's set to true) The docs say:
Whether the imported role can be modified by attaching policy resources to it.
Which is untrue. You may only modify the role by adding inline policies. Not managed policies.
https://github.com/aws/aws-cdk/blob/070f5ecebfba8a3f9b5771b251ee9b584aa89b67/packages/%40aws-cdk/aws-iam/lib/private/imported-role.ts#L70
the function addManagedPolicy for ImportedRole only adds a warning Not adding managed policy: ${policy.managedPolicyArn} to imported role: ${this.roleName}, is this a missing implementation or an intended behavior?
the warning isn't even really shown to the user, it just prints
[Warning at /MyStack/ImportedRole] [object Object]
Is there any other way to add an AWS Managed Policy to an Imported Role?
@jayhilden's solution could work, even if it requires to copy&paste the statements from a Managed Policy to a new one (handled by us).
In our case, we're needing the ReadOnlyAccess policy, so we're going to duplicate it while this issue is solved.
It would be nice to have this solved, in the meantime a solution like this works:
const statement = new PolicyStatement({
effect: Effect.ALLOW,
actions: ['execute-api:Invoke'],
resources: [
//SOME RESOURCE
],
});
const role = Role.fromRoleArn(this, 'role', 'arn:aws:iam::${props.account}:role/SOME_ROLE_NAME');
role.attachInlinePolicy(new Policy(
this,
'inline-policy', {
policyName: 'CustomPolicyName',
statements: [statement],
},
));
This shouldn't be marked as documentation issue, it rather should just be implemented - I don't see anything wrong in idea of adding managed policies to the imported role (for example to the auto-generated service roles).