AWS CDK:如何创建一个可被多个主体扮演的IAM角色?

35

我正在部署一项将被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类仅允许您最初指定一个假定负责人,例如:

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

所以我试图找到最好/最干净的方法来添加第二个主体。文档说我可以使用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来获取“更清晰”的策略声明?或者我只能接受它当前生成的这两个声明?


如果您正在使用CDK,为什么还要担心它的构建代码?只需按照CDK的方式编写IAM角色即可,这应该很容易阅读和扩展。我通常使用ServicePrincipal创建IAM角色,该角色将自动由某些资源调用,然后为此角色将使用的每个服务创建PolicyStatement语句。它提供了可扩展性,例如将来需要添加/删除服务,可以在不实际损害现有策略的情况下完成。 - Atul Kumar
@AtulKumar,你说得很有道理。我试图达到所需的策略是为了与现有角色和信任策略声明保持一致。我们大部分现有基础设施都是手动部署的,因此我希望尽可能与该设计/外观保持一致。 - Philip Colmer
2个回答

92

可以使用CompositePrincipal来完成此操作:

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

谢谢!CompositePrincipal为我解决了这个问题。 - user1653042
这个方法可以实现,但是有没有办法将每个主体合并成一个语句呢?CompsitePrincipal会生成多个语句,而不是一个包含多个主体的语句。 - undefined

0
使用案例:我打算将多个帐户负责人添加到可信关系中,以及服务负责人,以便权限不是完全开放的。我能够使用扩展运算符解决这个问题。
    const accountsToAllowAssumedBy = ['000000000000', '111111111111'];

    const role = new iam.Role(this, 'Role', {
      roleName: 'AssumeRoleTest',
      assumedBy: new iam.CompositePrincipal(
        new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
        ...accountsToAllowAssumedBy.map((account) => new iam.AccountPrincipal(account)), //Spread Operator (...)
      ),
    });

输出:

"Role1ABCC5F0": {
   "Type": "AWS::IAM::Role",
   "Properties": {
    "RoleName": "AssumeRoleTest",
    "AssumeRolePolicyDocument": {
     "Statement": [
      {
       "Action": "sts:AssumeRole",
       "Effect": "Allow",
       "Principal": {
        "AWS": [
         "arn:aws:iam::000000000000:root",
         "arn:aws:iam::111111111111:root"
        ],
        "Service": "ecs-tasks.amazonaws.com"
       }
      }
     ],
    },
   },
  },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接