question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

A Principal that represents an MFA-authenticated user

See original GitHub issue

When trying to define a role that is only assumable when MFA is set, the permission policy of the role can’t be modified but only complemented. This is due to the fact, that iam.Role has its argument assumed_by set as required, which automatically sets a policy statement in the permission policy. Later, when setting the MFA requirement via role.assume_role_policy.add_statements(iam.PolicyStatement(...)) it is required to set at least the arguments principals, actions, and conditions. The problem is that this adds another policy statement to the permission policy, which renders the MFA condition useless and allows bypassing it.

Reproduction Steps

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

Resulting permission policy

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

Expected permission policy

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

Technical Details

CDK version: 1.20.0

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:10 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
variiacommented, Feb 25, 2020

Not sure if it is better, but I found a reasonably simple way to add the missing condition:

from aws_cdk import (
    aws_iam as iam,
    core
)


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

        role = iam.Role(
            scope=self,
            id='Role',
            assumed_by=iam.CompositePrincipal(
                iam.AccountPrincipal("111111111111"),
                iam.AccountPrincipal("222222222222"),
            ),
            description='my Administrator role',
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name('AdministratorAccess'),
            ],
            max_session_duration=core.Duration.hours(8),
            path='/',
            role_name='MyAdmin'
        )

        # add (not yet supported) conditional statement
        cfn_resource = role.node.find_child('Resource')
        cfn_resource.add_override('Properties.AssumeRolePolicyDocument.Statement.0.Condition.Bool',
                                  {'aws:MultiFactorAuthPresent': True})

This is a generic way of adding any missing Properties from the intent-based constructor, down to the low level Cfn object

2reactions
rix0rrrcommented, Jan 15, 2020

You can solve this yourself by writing an class that implements IPrincipal which returns the policy fragment that you need.

Read more comments on GitHub >

github_iconTop Results From Across the Web

CloudTrail userIdentity element - AWS Documentation
The Amazon Resource Name (ARN) of the principal that made the call. ... mfaAuthenticated – The value is true if the root user...
Read more >
Policies and permissions in IAM - Amazon Identity and Access ...
Amazon evaluates these policies when an IAM principal (user or role) ... In this case, the Condition evaluates to true when the user...
Read more >
AWS IAM: Working, Components, and Features Explained
A principal is an entity that can perform actions on an AWS resource. ... or MFA-authenticated users to make changes to those buckets....
Read more >
Solving the AWS Roles Mystery | Authomize.com
Think about how someone can temporarily become a super user in Linux with the sudo command, and you get the general idea. The...
Read more >
AWS CloudTrail - Cyderes Documentation
AWS CloudTrail is an AWS service that helps you enable governance, compliance, and operational ... mfaAuthenticated, principal.user.labels.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found