Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS CDK: How to create an IAM role that can be assumed by multiple principals?

Tags:

aws-cdk

I'm deploying a Lambda function that will be used by CloudFront. The execution role for the function therefore needs to be assumed by edgelambda.amazonaws.com and lambda.amazonaws.com. If I was doing this by hand, the policy would look like this:

{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "Service": [
                "edgelambda.amazonaws.com",
                "lambda.amazonaws.com"
            ]
        },
        "Action": "sts:AssumeRole"
    }
    ]
}

When setting this up in AWS CDK, the iam.Role class only allows you to specify one assuming principal initially, e.g.:

lambda_role = iam.Role(
    self,
    "lambda_redirect_role",
    assumed_by=iam.ServicePrincipal("edgelambda.amazonaws.com"),
    managed_policies=[
        iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole"),
        iam.ManagedPolicy.from_aws_managed_policy_name("AWSXrayWriteOnlyAccess")
    ],
)

So I'm trying to find the best/cleanest way of adding the second principal. The documentation says that I can use assume_role_policy to retrieve the policy document and then manipulate that.

So I've tried:

policy = lambda_role.assume_role_policy
policy.add_statements(
    iam.PolicyStatement(
        actions=["sts:AssumeRole"],
        effect=iam.Effect.ALLOW,
        principals=[
            iam.ServicePrincipal("lambda.amazonaws.com")
        ]
    )
)

but that gives me this rather less-than-optimal policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "edgelambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

I've tried manipulating the existing statement within the policy but I can't figure out how to then get that back into the Role definition:

policy = lambda_role.assume_role_policy
# This gives us a read-only policy so we need to do
# some manipulation in order to add the lambda principal
policy_json = policy.to_json()
print(policy_json)
# That gets us a dict (even though it says json) so now
# we extract the one and only statement ...
statement = policy_json["Statement"][0]
# Turn it back into a CDK object we can manipulate
statement_obj = iam.PolicyStatement.from_json(statement)
# Add the extra principal
statement_obj.add_principals(
    iam.ServicePrincipal("lambda.amazonaws.com")
)
# Put it all back ...
policy_json["Statement"][0] = statement_obj.to_json()
policy.from_json(policy_json)

Is there a way to get to the "cleaner" policy statement with CDK or am I stuck with the two statements it is currently generating?

like image 744
Philip Colmer Avatar asked Jul 09 '21 07:07

Philip Colmer


People also ask

What is a composite principal?

CompositePrincipal (*principals) Bases: aws_cdk.aws_iam.PrincipalBase. Represents a principal that has multiple types of principals. A composite principal cannot have conditions. i.e. multiple ServicePrincipals that form a composite principal ExampleMetadata.

How do you allow an IAM role to assume another role?

You can assume a role by calling an AWS CLI or API operation or by using a custom URL. The method that you use determines who can assume the role and how long the role session can last. ¹ Using the credentials for one role to assume a different role is called role chaining.

Can you assume multiple roles AWS?

Technically, yes, there is a way to assume multiple IAM roles at the same time.


1 Answers

This can be done using CompositePrincipal:

lambda_role = iam.Role(
    self,
    "lambda_redirect_role",
    assumed_by=iam.CompositePrincipal(
        iam.ServicePrincipal("edgelambda.amazonaws.com"),
        iam.ServicePrincipal("lambda.amazonaws.com"),
    ),
    ...
)
like image 152
Okonos Avatar answered Oct 19 '22 14:10

Okonos