AWS CDK:如何创建可以由多个委托人担任的 IAM 角色?

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

我正在部署 CloudFront 将使用的 Lambda 函数。因此,函数的执行角色需要由 edgelambda.amazonaws.com 和 lambda.amazonaws.com 承担。如果我手动执行此操作,策略将如下所示:

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

在 AWS CDK 中进行设置时,iam.Role class 仅允许您最初指定一个假设主体,例如:

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")
    ],
)

所以我试图找到 best/cleanest 添加第二个主体的方法。文档说我可以使用 assume_role_policy 检索策略文档然后对其进行操作。

所以我试过了:

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

但这给了我这个不太理想的政策:

{
  "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"
    }
  ]
}

我已尝试在策略中操纵现有语句,但我不知道如何将其恢复到角色定义中:

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)

有没有办法使用 CDK 获得“更清晰”的政策声明,或者我是否坚持使用它当前生成的两个声明?

这可以使用 CompositePrincipal:

lambda_role = iam.Role(
    self,
    "lambda_redirect_role",
    assumed_by=iam.CompositePrincipal(
        iam.ServicePrincipal("edgelambda.amazonaws.com"),
        iam.ServicePrincipal("lambda.amazonaws.com"),
    ),
    ...
)