简体   繁体   English

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

[英]Creating an MFA-protected role with AWS CDK bypasses MFA condition

I am trying to create an MFA-protected role granting AdministratorAccess which can be assumed by another user.我正在尝试创建一个受 MFA 保护的角色,授予可由其他用户承担的AdministratorAccess I can get it to define the user and the permission policy of the role.我可以用它来定义角色的用户和权限策略。 However, when I define the MFA requirement, the principal and the permitted action is duplicated in the permission policy, which renders the MFA requirement condition useless.但是,当我定义 MFA 要求时,主体和允许的操作在权限策略中重复,这使得 MFA 要求条件无用。

My CDK code looks like this:我的 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]))

The resulting permission policy of the role then looks as follows:生成的角色权限策略如下所示:

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

This is not what I want, because - as mentioned above - the user will be able to assume the role even without MFA present.这不是我想要的,因为 - 如上所述 - 即使没有 MFA,用户也可以承担该角色。 What I want is the following:我想要的是以下内容:

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

I already tried defining the role without the assumed_by argument and adding the principal in the assume_role_policy instead, but a principal is required by the iam.Role class.我已经尝试过定义,而不作用assumed_by在参数和添加的主要assume_role_policy代替,而是由需要的主要iam.Role类。 Similarly, iam.PolicyStatement in assume_role_policy.add_statements() does not allow leaving out either the principals or the actions argument.类似地, iam.PolicyStatement assume_role_policy.add_statements()中的assume_role_policy.add_statements()不允许assume_role_policy.add_statements() principalsactions参数。

How can I create the role's permission policy without redundancies and without rendering conditions useless because of them?如何创建角色的权限策略而不会造成冗余并且不会因为它们而使条件变得无用?

It looks like there is no way to update the existing trust policy.看起来没有办法更新现有的信任策略。 You can possibly raise an issue on Github .您可以在Github上提出问题。

As a workaround, you can set AccountRootPrincipal as the trusted principal when defining the role, so the user cannot assume it without MFA.作为一种解决方法,您可以在定义角色时将 AccountRootPrincipal 设置为受信任的主体,这样用户在没有 MFA 的情况下无法承担它。

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

I figured it out now.我现在想通了。 The solution is a combination of the one proposed by @Vikyol and the hints by the kind people over at this Github issue :解决方案是@Vikyol 提出的解决方案和好心人在这个 Github 问题上的提示的组合:

You have to create a class that inherits from iam.AccountRootPrincipal and overrides the property policy_fragment so that the returned trust policy contains the Conditions block:您必须创建一个继承自iam.AccountRootPrincipal并覆盖属性policy_fragment的类,以便返回的信任策略包含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]))

Note that this doesn't allow for trusting accounts other than the one where the user & role are defined.请注意,除了定义用户和角色的帐户之外,这不允许信任帐户。 However, this can be solved easily by passing an account number or instance of core.Environment as an argument to the AssumeRoleStack initializer.但是,这可以通过将帐号或core.Environment实例作为参数传递给AssumeRoleStack初始值设定项来轻松解决。 Passing this down to the initializer of MFAAccountRootPrincipal you can then manually construct the ARN of the trusted account's root user.将此传递给MFAAccountRootPrincipal的初始值MFAAccountRootPrincipal ,然后您可以手动构建受信任账户的 root 用户的 ARN。

Why invent your own methods when the capability exists in CDK natively?当 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
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM