I am trying to create a role with the following policy document:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "${aws_iam_role.eks_nodes.arn}",
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
The problem, however, is that the Role construct only takes a single entity for assumedBy
.
const defaultPodRole = new iam.Role(this, "default-pod-role", {
roleName: "default",
path: "/pods/",
assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
})
I tried pulling out the assumeRolePolicy
but its statements
member is private, and that would involve digging around in the statements
array anyway.
export declare class PolicyDocument extends Token {
private readonly baseDocument?;
private statements;
This workaround produces a role/policy/trust setup that collapses to the same interpretation, but the resulting document is not the same.
const role = new iam.Role(this, 'Role', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
if ( role.assumeRolePolicy ) {
role.assumeRolePolicy.addStatement(new iam.PolicyStatement().
addAccountRootPrincipal().
addAction('sts:AssumeRole'));
}
The resulting document is this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456123456:root"
},
"Action": "sts:AssumeRole"
}
]
}
This is indeed a limitation. Technically we can provide an implementation of PolicyPrincipal
that will allow combining multiple principals.
@ijcd can you share a bit more details about your use case? Why do you need this?
@eladb https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-permissions.html#lambda-edge-permissions-function-execution recommends using two principals
Thanks @eamonnfaherty, exactly what I was after.
Is there any progress in this issue? I do also need this feature to connect my API Gateway directly to an DynmoDB Table. 馃槬
@deen13 PR pending
To be honest for the example I specified I would like to see that working via a construct.
Generally, allowing a role to be assumed by two services is a sign that the author is breaking least privileged principle.
@deen13 can you provide some reference to your use case please?
https://github.com/eamonnfaherty Nevertheless, we rather not be opinionated in the low level IAM library. Higher level AWS constructs synthesize policies based on least privilege but if users want to define less restrictive policies for some reason they should be able to do that with the CDK.
Fair enough.
According to https://github.com/aws/aws-cdk/pull/1377, the way to do this is by using a CompositePrincipal
object. (Surely changing Role.assumed_by
to accept a list or adding a new method to Role
would've been more obvious).
E.g. In Python:
pipeline_role = aws_iam.Role(
scope=self, id=f'pipeline-role',
role_name='pipeline',
assumed_by=aws_iam.CompositePrincipal(
aws_iam.ServicePrincipal('datapipeline.amazonaws.com'),
aws_iam.ServicePrincipal('elasticmapreduce.amazonaws.com')
)
)
@eladb Use case system manager automation document.
Here the example provides ssm and ec2 service principals.
It's also in the Systems Manager user guide.
I also was only able to resolve this by searching and finding this Github issue.
It would be easier if this was better documented in the docs itself for assumed_by in Role.
Another example:
const dmsAccessForEndpointRole = new iam.Role(this, 'DmsAccessForEndpointRole', {
roleName: 'dms-access-for-endpoint',
assumedBy: dmsServicePrincipal,
});
dmsAccessForEndpointRole.assumeRolePolicy?.addStatements(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
principals: [new iam.ServicePrincipal('redshift.amazonaws.com')],
actions: ['sts:AssumeRole'],
}),
);
Most helpful comment
According to https://github.com/aws/aws-cdk/pull/1377, the way to do this is by using a
CompositePrincipal
object. (Surely changingRole.assumed_by
to accept a list or adding a new method toRole
would've been more obvious).E.g. In Python: