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?
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.
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.
Technically, yes, there is a way to assume multiple IAM roles at the same time.
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"),
),
...
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With