使用 AWS CDK 创建受 MFA 保护的角色绕过 MFA 条件

Creating an MFA-protected role with AWS CDK bypasses MFA condition

我正在尝试创建一个受 MFA 保护的角色授予 AdministratorAccess 可以由另一个用户承担。我可以得到它来定义用户和角色的权限策略。但是,当我定义MFA需求时,委托人和允许的操作在权限策略中重复,导致MFA需求条件无用。

我的 CDK 代码如下所示:

from aws_cdk import (
    aws_iam as iam,
    core,
)


class AssumeRoleStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        user = iam.User(self, 'myuser')
        role = iam.Role(self, 'myrole',
                        assumed_by=iam.ArnPrincipal(user.user_arn),
                        max_session_duration=core.Duration.hours(8))
        role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AdministratorAccess'))
        role.assume_role_policy.add_statements(
            iam.PolicyStatement(principals=[user],
                                actions=['sts:AssumeRole'],
                                conditions={'Bool': {'aws:MultiFactorAuthPresent': True}})
        )
        user.add_to_policy(iam.PolicyStatement(actions=['sts:AssumeRole'], resources=[role.role_arn]))

角色的最终权限策略如下所示:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::012345678910:user/assume-role-myuserZ09A543B-1ULCILBM447SF"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::012345678910:user/assume-role-myuserZ09A543B-1ULCILBM447SF"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

这不是我想要的,因为 - 如上所述 - 即使没有 MFA,用户也可以担任该角色。我想要的是以下内容:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::012345678910:user/assume-role-myuserZ09A543B-1ULCILBM447SF"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

我已经尝试在不使用 assumed_by 参数的情况下定义角色,而是在 assume_role_policy 中添加委托人,但是 iam.Role class 需要委托人。同样,assume_role_policy.add_statements() 中的 iam.PolicyStatement 不允许遗漏 principalsactions 参数。

我如何创建角色的权限策略而不冗余且渲染条件不会因为它们而变得无用?

似乎无法更新现有的信任策略。您可以在 Github.

上提出问题

作为解决方法,您可以在定义角色时将 AccountRootPrincipal 设置为受信任的委托人,这样用户就无法在没有 MFA 的情况下承担它。

iam.Role(
   assumed_by=iam.AccountRootPrincipal()
)

我现在明白了。该解决方案结合了@Vikyol 提出的解决方案和 this Github issue:

的好心人的提示

您必须创建一个继承自 iam.AccountRootPrincipal 并覆盖 属性 policy_fragment 的 class,以便返回的信任策略包含 Conditions 块:

from aws_cdk import (
    aws_iam as iam,
    core,
)


class MFAAccountRootPrincipal(iam.AccountRootPrincipal):
    def __init__(self):
        super().__init__()

    @property
    def policy_fragment(self) -> iam.PrincipalPolicyFragment:
        return iam.PrincipalPolicyFragment(
            principal_json={'AWS': [self.arn]},
            conditions={'Bool': {'aws:MultiFactorAuthPresent': True}}
        )


class AssumeRoleStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        user = iam.User(self, 'myuser')
        role = iam.Role(self, 'MFA_Admin_Role',
                        assumed_by=MFAAccountRootPrincipal(),
                        managed_policies=[iam.ManagedPolicy.from_aws_managed_policy_name('AdministratorAccess')],
                        max_session_duration=core.Duration.hours(8))
        user.add_to_policy(iam.PolicyStatement(actions=['sts:AssumeRole'], resources=[role.role_arn]))

请注意,除定义了用户和角色的帐户外,这不允许信任其他帐户。但是,通过将帐号或 core.Environment 的实例作为参数传递给 AssumeRoleStack 初始值设定项,可以轻松解决此问题。将其传递给 MFAAccountRootPrincipal 的初始化程序,然后您可以手动构建受信任帐户的根用户的 ARN。

既然 CDK 本身就有这种能力,为什么还要发明自己的方法?

role = iam.Role(
    self,
    "RoleWithCondition",
    description="Role insisting on MFA",
    assumed_by=iam.PrincipalWithConditions(
        principal=iam.AccountPrincipal("123456789012").grant_principal,
        conditions={
            "Bool":  {
                "aws:MultiFactorAuthPresent": True,
            },
        },
    ).grant_principal
)