Esempio n. 1
0
def get_sqs_queue_policies(
        session: botocore.session.Session,
        account_id: str,
        region_allow_list: Optional[List[str]] = None,
        region_deny_list: Optional[List[str]] = None) -> List[Policy]:
    """Using a botocore Session object, return a list of Policy objects representing the queue policies of each
    SQS queue in this account.

    The region allow/deny lists are mutually-exclusive (i.e. at least one of which has the value None) lists of
    allowed/denied regions to pull data from.
    """
    result = []

    # Iterate through all regions of SQS where possible
    for sqs_region in get_regions_to_search(session, 'sqs', region_allow_list,
                                            region_deny_list):
        try:
            # Grab the queue names
            queue_urls = []
            sqsclient = session.create_client('sqs', region_name=sqs_region)
            response = sqsclient.list_queues()
            if 'QueueUrls' in response:
                queue_urls.extend(response['QueueUrls'])
            else:
                continue

            # Grab the queue policies
            for queue_url in queue_urls:
                queue_name = queue_url.split('/')[-1]
                sqs_policy_response = sqsclient.get_queue_attributes(
                    QueueUrl=queue_url, AttributeNames=['Policy'])
                if 'Policy' in sqs_policy_response:
                    sqs_policy_doc = json.loads(sqs_policy_response['Policy'])
                    result.append(
                        Policy(
                            'arn:aws:sqs:{}:{}:{}'.format(
                                sqs_region, account_id, queue_name),
                            queue_name, json.loads(sqs_policy_doc)))
                    logger.info('Caching policy for {}'.format(
                        'arn:aws:sqs:{}:{}:{}'.format(sqs_region, account_id,
                                                      queue_name)))
                else:
                    result.append(
                        Policy(
                            'arn:aws:sqs:{}:{}:{}'.format(
                                sqs_region, account_id, queue_name),
                            queue_name, {
                                "Statement": [],
                                "Version": "2012-10-17"
                            }))
                    logger.info(
                        'Queue {} does not have a bucket policy, adding a "stub" policy instead.'
                        .format(queue_name))
        except botocore.exceptions.ClientError as ex:
            logger.info(
                'Unable to search SQS in region {} for queues. The region may be disabled, or the current principal may not be authorized to access the service. Continuing.'
                .format(sqs_region))
            logger.debug('Exception was: {}'.format(ex))

    return result
Esempio n. 2
0
def get_s3_bucket_policies(session: botocore.session.Session) -> List[Policy]:
    """Using a botocore Session object, return a list of Policy objects representing the bucket policies of each
    S3 bucket in this account.
    """
    result = []
    s3client = session.create_client('s3')
    buckets = [x['Name'] for x in s3client.list_buckets()['Buckets']]
    for bucket in buckets:
        bucket_arn = 'arn:aws:s3:::{}'.format(
            bucket)  # TODO: allow different partition
        try:
            bucket_policy = json.loads(
                s3client.get_bucket_policy(Bucket=bucket)['Policy'])
            result.append(Policy(bucket_arn, bucket, bucket_policy))
            logger.info('Caching policy for {}'.format(bucket_arn))
        except botocore.exceptions.ClientError as ex:
            if 'NoSuchBucketPolicy' in str(ex):
                logger.info(
                    'Bucket {} does not have a bucket policy, adding a "stub" policy instead.'
                    .format(bucket))
                result.append(
                    Policy(bucket_arn, bucket, {
                        "Statement": [],
                        "Version": "2012-10-17"
                    }))
            else:
                logger.info(
                    'Unable to retrieve bucket policy for {}. You should add this manually. Continuing.'
                    .format(bucket))
            logger.debug('Exception was: {}'.format(ex))

    return result
Esempio n. 3
0
def build_playground_graph() -> Graph:
    """Constructs and returns a Graph objects with many nodes, edges, groups, and policies"""
    common_iam_prefix = 'arn:aws:iam::000000000000:'

    # policies to use and add
    admin_policy = Policy('arn:aws:iam::aws:policy/AdministratorAccess', 'AdministratorAccess', _get_admin_policy())
    ec2_for_ssm_policy = Policy('arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM', 'AmazonEC2RoleforSSM',
                                _get_ec2_for_ssm_policy())
    s3_full_access_policy = Policy('arn:aws:iam::aws:policy/AmazonS3FullAccess', 'AmazonS3FullAccess',
                                   _get_s3_full_access_policy())
    jump_policy = Policy('arn:aws:iam::000000000000:policy/JumpPolicy', 'JumpPolicy', _get_jump_policy())
    policies = [admin_policy, ec2_for_ssm_policy, s3_full_access_policy, jump_policy]

    # IAM role trust docs to be used
    ec2_trusted_policy_doc = _make_trust_document({'Service': 'ec2.amazonaws.com'})
    root_trusted_policy_doc = _make_trust_document({'AWS': 'arn:aws:iam::000000000000:root'})
    alt_root_trusted_policy_doc = _make_trust_document({'AWS': '000000000000'})
    other_acct_trusted_policy_doc = _make_trust_document({'AWS': '999999999999'})

    # nodes to add
    nodes = []
    # Regular admin user
    nodes.append(Node(common_iam_prefix + 'user/admin', 'AIDA00000000000000000', [admin_policy], [], None, None, 1, True, True))

    # Regular ec2 role
    nodes.append(Node(common_iam_prefix + 'role/ec2_ssm_role', 'AIDA00000000000000001', [ec2_for_ssm_policy], [],
                      ec2_trusted_policy_doc, common_iam_prefix + 'instance-profile/ec2_ssm_role', 0, False, False))

    # ec2 role with admin
    nodes.append(Node(common_iam_prefix + 'role/ec2_admin_role', 'AIDA00000000000000002', [ec2_for_ssm_policy], [], ec2_trusted_policy_doc,
                      common_iam_prefix + 'instance-profile/ec2_admin_role', 0, False, True))

    # assumable role with s3 access
    nodes.append(Node(common_iam_prefix + 'role/s3_access_role', 'AIDA00000000000000003', [s3_full_access_policy], [], root_trusted_policy_doc,
                      None, 0, False, False))

    # second assumable role with s3 access with alternative trust policy
    nodes.append(Node(common_iam_prefix + 'role/s3_access_role_alt', 'AIDA00000000000000004', [s3_full_access_policy], [],
                 alt_root_trusted_policy_doc, None, 0, False, False))

    # externally assumable role with s3 access
    nodes.append(Node(common_iam_prefix + 'role/external_s3_access_role', 'AIDA00000000000000005', [s3_full_access_policy], [],
                      other_acct_trusted_policy_doc, None, 0, False, False))

    # jump user with access to sts:AssumeRole
    nodes.append(Node(common_iam_prefix + 'user/jumpuser', 'AIDA00000000000000006', [jump_policy], [], None, None, 1, True, False))

    # user with S3 access, path in user's ARN
    nodes.append(Node(common_iam_prefix + 'user/somepath/some_other_jumpuser', 'AIDA00000000000000007', [jump_policy],
                      [], None, None, 1, True, False))

    # role with S3 access, path in role's ARN
    nodes.append(Node(common_iam_prefix + 'role/somepath/somerole', 'AIDA00000000000000008', [s3_full_access_policy],
                      [], alt_root_trusted_policy_doc, None, 0, False, False))

    # edges to add
    edges = obtain_edges(None, checker_map.keys(), nodes, sys.stdout, True)

    return Graph(nodes, edges, policies, [], _get_default_metadata())
Esempio n. 4
0
    def _get_scps_for_target(target_id: str) -> List[Policy]:
        """This method takes an ID for a target (root, OU, or account), then composes and returns a list of Policy
        objects for that target."""
        scps_result = []
        policy_name_arn_list = []
        list_policies_paginator = orgsclient.get_paginator(
            'list_policies_for_target')
        for lpp_page in list_policies_paginator.paginate(
                TargetId=target_id, Filter='SERVICE_CONTROL_POLICY'):
            for policy in lpp_page['Policies']:
                policy_name_arn_list.append((policy['Name'], policy['Arn']))

        for name_arn_pair in policy_name_arn_list:
            policy_name, policy_arn = name_arn_pair
            desc_policy_resp = orgsclient.describe_policy(
                PolicyId=policy_arn.split('/')[-1])
            scps_result.append(
                Policy(policy_arn, policy_name,
                       json.loads(desc_policy_resp['Policy']['Content'])))

        logger.debug('SCPs of {}: {}'.format(target_id,
                                             [x.arn for x in scps_result]))

        scp_list.extend(scps_result)
        return scps_result
    def test_admin_verified_for_group_member(self):
        admin_policy = Policy(
            'arn:aws:iam::000000000000:group/admins', 'inline_admin', {
                'Version': '2012-10-17',
                'Statement': [{
                    'Effect': 'Allow',
                    'Action': '*',
                    'Resource': '*'
                }]
            })

        admin_group = Group('arn:aws:iam::000000000000:group/admins',
                            [admin_policy])
        not_admin_group = Group('arn:aws:iam::000000000000:group/losers', [])

        new_node_1 = Node('arn:aws:iam::000000000000:user/node_1', 'id1', [],
                          [admin_group], None, None, 1, False, False, None,
                          False, None)
        new_node_2 = Node('arn:aws:iam::000000000000:user/node_2', 'id2', [],
                          [not_admin_group], None, None, 1, False, False, None,
                          False, None)

        update_admin_status([new_node_1, new_node_2])

        self.assertTrue(new_node_1.is_admin,
                        'Member of admin group should be marked as an admin')
        self.assertFalse(
            new_node_2.is_admin,
            'Member of non-admin group should not be marked as an admin')
Esempio n. 6
0
def build_graph_with_one_admin() -> Graph:
    """Constructs and returns a Graph object with one node that is an admin"""
    admin_user_arn = 'arn:aws:iam::000000000000:user/admin'
    policy = Policy(admin_user_arn, 'InlineAdminPolicy', _get_admin_policy())
    node = Node(admin_user_arn, 'AIDA00000000000000000', [policy], [], None,
                None, 1, True, True, None, False, None)
    return Graph([node], [], [policy], [], _get_default_metadata())
Esempio n. 7
0
def _build_user_with_policy(policy_dict,
                            policy_name='single_user_policy',
                            user_name='asdf',
                            number='0') -> Node:
    """Helper function: builds an IAM User with a given input policy."""
    policy = Policy('arn:aws:iam::000000000000:policy/{}'.format(policy_name),
                    policy_name, policy_dict)
    result = Node('arn:aws:iam::000000000000:user/{}'.format(user_name),
                  'AIDA0000000000000000{}'.format(number), [policy], [], None,
                  None, 1, True, False, None, False, None)
    return result
    def test_admin_verified_by_inline_policies(self):
        admin_policy = Policy(
            'arn:aws:iam::000000000000:user/user_1', 'inline_admin', {
                'Version': '2012-10-17',
                'Statement': [{
                    'Effect': 'Allow',
                    'Action': '*',
                    'Resource': '*'
                }]
            })

        not_admin_policy = Policy(
            'arn:aws:iam::000000000000:user/user_2', 'inline_not_admin', {
                'Version':
                '2012-10-17',
                'Statement': [{
                    'Effect': 'Allow',
                    'Action': '*',
                    'Resource': '*'
                }, {
                    'Effect': 'Deny',
                    'Action': '*',
                    'Resource': '*'
                }]
            })

        new_node_1 = Node('arn:aws:iam::000000000000:user/user_1', 'id1',
                          [admin_policy], [], None, None, 1, False, False,
                          None, False, None)
        new_node_2 = Node('arn:aws:iam::000000000000:user/user_2', 'id2',
                          [not_admin_policy], [], None, None, 1, False, False,
                          None, False, None)

        update_admin_status([new_node_1, new_node_2])

        self.assertTrue(new_node_1.is_admin,
                        'User with admin policy should be marked as an admin')
        self.assertFalse(
            new_node_2.is_admin,
            'User with non-admin policy should not be marked as an admin')
Esempio n. 9
0
def get_sns_topic_policies(
        session: botocore.session.Session,
        region_allow_list: Optional[List[str]] = None,
        region_deny_list: Optional[List[str]] = None,
        client_args_map: Optional[dict] = None) -> List[Policy]:
    """Using a botocore Session object, return a list of Policy objects representing the topic policies of each
    SNS topic in this account.

    The region allow/deny lists are mutually-exclusive (i.e. at least one of which has the value None) lists of
    allowed/denied regions to pull data from.
    """
    result = []

    snsargs = client_args_map.get('sns', {})

    # Iterate through all regions of SNS where possible
    for sns_region in get_regions_to_search(session, 'sns', region_allow_list,
                                            region_deny_list):
        try:
            # Grab the topics
            topics = []
            snsclient = session.create_client('sns',
                                              region_name=sns_region,
                                              **snsargs)
            sns_paginator = snsclient.get_paginator('list_topics')
            for page in sns_paginator.paginate():
                topics.extend([x['TopicArn'] for x in page['Topics']])

            # Grab the topic policies
            for topic in topics:
                policy_str = snsclient.get_topic_attributes(
                    TopicArn=topic)['Attributes']['Policy']
                result.append(
                    Policy(
                        topic,
                        topic.split(':')
                        [-1],  # SNS Topic ARN Format: arn:<partition>:sns:<region>:<account>:<Topic Name>
                        json.loads(policy_str)))
                logger.info('Caching policy for {}'.format(topic))
        except botocore.exceptions.ClientError as ex:
            logger.info(
                'Unable to search SNS in region {} for topic policies. The region may be disabled, or the current principal may not be authorized to access the service. Continuing.'
                .format(sns_region))
            logger.debug('Exception was: {}'.format(ex))
            continue

    return result
Esempio n. 10
0
def get_kms_key_policies(
        session: botocore.session.Session,
        region_allow_list: Optional[List[str]] = None,
        region_deny_list: Optional[List[str]] = None,
        client_args_map: Optional[dict] = None) -> List[Policy]:
    """Using a botocore Session object, return a list of Policy objects representing the key policies of each
    KMS key in this account.

    The region allow/deny lists are mutually-exclusive (i.e. at least one of which has the value None) lists of
    allowed/denied regions to pull data from.
    """
    result = []

    kmsargs = client_args_map.get('kms', {})

    # Iterate through all regions of KMS where possible
    for kms_region in get_regions_to_search(session, 'kms', region_allow_list,
                                            region_deny_list):
        try:
            # Grab the keys
            cmks = []
            kmsclient = session.create_client('kms',
                                              region_name=kms_region,
                                              **kmsargs)
            kms_paginator = kmsclient.get_paginator('list_keys')
            for page in kms_paginator.paginate():
                cmks.extend([x['KeyArn'] for x in page['Keys']])

            # Grab the key policies
            for cmk in cmks:
                policy_str = kmsclient.get_key_policy(
                    KeyId=cmk, PolicyName='default')['Policy']
                result.append(
                    Policy(
                        cmk,
                        cmk.split('/')
                        [-1],  # CMK ARN Format: arn:<partition>:kms:<region>:<account>:key/<Key ID>
                        json.loads(policy_str)))
                logger.info('Caching policy for {}'.format(cmk))
        except botocore.exceptions.ClientError as ex:
            logger.info(
                'Unable to search KMS in region {} for key policies. The region may be disabled, or the current principal may not be authorized to access the service. Continuing.'
                .format(kms_region))
            logger.debug('Exception was: {}'.format(ex))
            continue

    return result
    def test_permissions_boundary_no_resource_policy(self):
        """In the case of no resource policy, the effective permissions are the "intersection" of the caller's
        identity policies + the boundary policy. Both the user's identity policies + boundary policy must
        permit the API call. A matching deny statement in either set will deny the whole call.
        """
        boundary = Policy(
            'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess',
            'AmazonS3ReadOnlyAccess',
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Action": [
                            "s3:Get*",
                            "s3:List*"
                        ],
                        "Resource": "*",
                        "Effect": "Allow"
                    }
                ]
            }
        )

        iam_user_1 = _build_user_with_policy(
            {
                'Version': '2012-10-17',
                'Statement': [{
                    'Effect': 'Allow',
                    'Action': '*',
                    'Resource': '*'
                }]
            },
            'admin_policy',
            'asdf1',
            '1'
        )

        iam_user_1.permissions_boundary = boundary

        self.assertTrue(
            local_check_authorization(iam_user_1, 's3:GetObject', 'arn:aws:s3:::bucket/object', {})
        )

        self.assertFalse(
            local_check_authorization(iam_user_1, 's3:PutObject', 'arn:aws:s3:::bucket/object', {})
        )
Esempio n. 12
0
def get_policies_and_fill_out(iamclient,
                              nodes: List[Node],
                              groups: List[Group],
                              output: io.StringIO = os.devnull,
                              debug=False) -> List[Policy]:
    """Using an IAM.Client object, return a list of Policy objects. Adds references to each passed Node and
    Group object where applicable.

    Writes high-level progress information to parameter output
    """
    result = []

    # navigate through nodes and add policy objects if they do not already exist in result
    output.write("Obtaining policies used by all IAM users and roles\n")
    for node in nodes:
        node_name_components = arns.get_resource(node.arn).split('/')
        node_type, node_name = node_name_components[0], node_name_components[
            -1]
        dprint(debug, 'Grabbing inline policies for {}'.format(node.arn))
        # get inline policies
        if node_type == 'user':
            inline_policy_arns = iamclient.list_user_policies(
                UserName=node_name)
            # get each inline policy, append it to node's policies and result list
            for policy_name in inline_policy_arns['PolicyNames']:
                dprint(debug,
                       '   Grabbing inline policy: {}'.format(policy_name))
                inline_policy = iamclient.get_user_policy(
                    UserName=node_name, PolicyName=policy_name)
                policy_object = Policy(
                    arn=node.arn,
                    name=policy_name,
                    policy_doc=inline_policy['PolicyDocument'])
                node.attached_policies.append(policy_object)
                result.append(policy_object)
        elif node_type == 'role':
            inline_policy_arns = iamclient.list_role_policies(
                RoleName=node_name)
            # get each inline policy, append it to the node's policies and result list
            # in hindsight, it's possible this could be folded with the above code, assuming the API doesn't change
            for policy_name in inline_policy_arns['PolicyNames']:
                dprint(debug,
                       '   Grabbing inline policy: {}'.format(policy_name))
                inline_policy = iamclient.get_role_policy(
                    RoleName=node_name, PolicyName=policy_name)
                policy_object = Policy(
                    arn=node.arn,
                    name=policy_name,
                    policy_doc=inline_policy['PolicyDocument'])
                node.attached_policies.append(policy_object)
                result.append(policy_object)

        # get attached policies for users and roles
        if node_type == 'user':
            attached_policies = iamclient.list_attached_user_policies(
                UserName=node_name)
        else:  # node_type == 'role':
            attached_policies = iamclient.list_attached_role_policies(
                RoleName=node_name)
        for attached_policy in attached_policies['AttachedPolicies']:
            policy_arn = attached_policy['PolicyArn']
            dprint(debug, '   Grabbing managed policy: {}'.format(policy_arn))
            # reduce API calls, search existing policies for matching arns
            policy_object = _get_policy_by_arn(policy_arn, result)
            if policy_object is None:
                # Gotta retrieve the policy's current default version
                dprint(debug, '      Policy cache miss, calling API')
                policy_response = iamclient.get_policy(PolicyArn=policy_arn)
                dprint(
                    debug, '      Policy version: {}'.format(
                        policy_response['Policy']['DefaultVersionId']))
                policy_version_response = iamclient.get_policy_version(
                    PolicyArn=policy_arn,
                    VersionId=policy_response['Policy']['DefaultVersionId'])
                policy_object = Policy(
                    arn=policy_arn,
                    name=policy_response['Policy']['PolicyName'],
                    policy_doc=policy_version_response['PolicyVersion']
                    ['Document'])
                result.append(policy_object)
            node.attached_policies.append(policy_object)

    output.write("Obtaining policies used by IAM groups\n")
    for group in groups:
        group_name = arns.get_resource(group.arn).split(
            '/', 1)[-1]  # split by slashes and take the final item
        dprint(debug, 'Getting policies for: {}'.format(group.arn))
        # get inline policies
        inline_policies = iamclient.list_group_policies(GroupName=group_name)
        for policy_name in inline_policies['PolicyNames']:
            dprint(debug, '   Grabbing inline policy: {}'.format(policy_name))
            inline_policy = iamclient.get_group_policy(GroupName=group_name,
                                                       PolicyName=policy_name)
            policy_object = Policy(arn=group.arn,
                                   name=policy_name,
                                   policy_doc=inline_policy['PolicyDocument'])
            group.attached_policies.append(policy_object)
            result.append(policy_object)

        # get attached policies
        attached_policies = iamclient.list_attached_group_policies(
            GroupName=group_name)
        for attached_policy in attached_policies['AttachedPolicies']:
            policy_arn = attached_policy['PolicyArn']
            dprint(debug, '   Grabbing managed policy: {}'.format(policy_arn))
            # check cached policies first
            policy_object = _get_policy_by_arn(policy_arn, result)
            if policy_object is None:
                dprint(debug, '      Policy cache miss, calling API')
                policy_response = iamclient.get_policy(PolicyArn=policy_arn)
                dprint(
                    debug, '      Policy version: {}'.format(
                        policy_response['Policy']['DefaultVersionId']))
                policy_version_response = iamclient.get_policy_version(
                    PolicyArn=policy_arn,
                    VersionId=policy_response['Policy']['DefaultVersionId'])
                policy_object = Policy(
                    arn=policy_arn,
                    name=policy_response['Policy']['PolicyName'],
                    policy_doc=policy_version_response['PolicyVersion']
                    ['Document'])
                result.append(policy_object)
            group.attached_policies.append(policy_object)

    return result
Esempio n. 13
0
def get_nodes_groups_and_policies(iamclient) -> dict:
    """Using an IAM.Client object, return a dictionary containing nodes, groups, and policies to be
    added to a Graph object. Admin status for the nodes are not updated.

    Writes high-level information on progress to the output stream.
    """
    logger.info('Obtaining IAM Users/Roles/Groups/Policies in the account.')
    result_paginator = iamclient.get_paginator(
        'get_account_authorization_details')
    user_results = []
    group_results = []
    role_results = []
    policy_results = []
    for page in result_paginator.paginate():
        user_results += page['UserDetailList']
        group_results += page['GroupDetailList']
        role_results += page['RoleDetailList']
        policy_results += page['Policies']

    logger.info(
        'Sorting users, roles, groups, policies, and their relationships.')

    # this is the result we return: dictionary with nodes/groups/users all filled out
    result = {'nodes': [], 'groups': [], 'policies': []}

    for p in policy_results:
        # go through each policy and update policy_results
        doc = [
            x['Document'] for x in p['PolicyVersionList']
            if x['IsDefaultVersion']
        ][0]
        result['policies'].append(Policy(p['Arn'], p['PolicyName'], doc))

    for g in group_results:
        # go through all inline policies and update policy_results
        group_policies = []
        if 'GroupPolicyList' in g:  # have to key-check these
            for p in g['GroupPolicyList']:
                group_policies.append(
                    Policy(
                        g['Arn'],  # inline policies get the same Arn as their principal
                        p['PolicyName'],
                        p['PolicyDocument']))
            result[
                'policies'] += group_policies  # this is just adding the inline policies for the group

        for p in g['AttachedManagedPolicies']:
            group_policies.append(
                _get_policy_by_arn_or_raise(p['PolicyArn'],
                                            result['policies']))

        result['groups'].append(Group(g['Arn'], group_policies))

    for u in user_results:
        # go through all inline policies and update policy_results
        user_policies = []
        if 'UserPolicyList' in u:  # have to key-check these
            for p in u['UserPolicyList']:
                user_policies.append(
                    Policy(
                        u['Arn'],  # inline policies inherit the Arn of their principal for the purposes of tracking
                        p['PolicyName'],
                        p['PolicyDocument']))
            result['policies'] += user_policies

        for p in u['AttachedManagedPolicies']:
            user_policies.append(
                _get_policy_by_arn_or_raise(p['PolicyArn'],
                                            result['policies']))

        if 'PermissionsBoundary' in u:
            boundary_policy = _get_policy_by_arn_or_raise(
                u['PermissionsBoundary']['PermissionsBoundaryArn'],
                result['policies'])
        else:
            boundary_policy = None

        group_list = []
        for group_name in u['GroupList']:
            for group in result['groups']:
                if arns.get_resource(group.arn).split('/')[-1] == group_name:
                    group_list.append(group)
                    break

        _tags = {}
        if 'Tags' in u:
            for tag in u['Tags']:
                _tags[tag['Key']] = tag['Value']

        # still need to figure out access keys
        result['nodes'].append(
            Node(u['Arn'], u['UserId'], user_policies, group_list, None, None,
                 0, 'PasswordLastUsed' in u, False, boundary_policy, False,
                 _tags))

    for r in role_results:
        # go through all inline policies and update policy_results
        role_policies = []
        for p in r['RolePolicyList']:
            role_policies.append(
                Policy(
                    r['Arn'],  # inline policies inherit the Arn of their principal for the purposes of tracking
                    p['PolicyName'],
                    p['PolicyDocument']))
        result['policies'] += role_policies

        for p in r['AttachedManagedPolicies']:
            role_policies.append(
                _get_policy_by_arn_or_raise(p['PolicyArn'],
                                            result['policies']))

        _tags = {}
        if 'Tags' in r:
            for tag in r['Tags']:
                _tags[tag['Key']] = tag['Value']

        result['nodes'].append(
            Node(r['Arn'], r['RoleId'], role_policies, None,
                 r['AssumeRolePolicyDocument'],
                 [x['Arn'] for x in r['InstanceProfileList']], 0, False, False,
                 None, False, _tags))

    logger.info("Obtaining Access Keys data for IAM users")
    for node in result['nodes']:
        if arns.get_resource(node.arn).startswith('user/'):
            # Grab access-key count and update node
            user_name = arns.get_resource(node.arn)[5:]
            if '/' in user_name:
                user_name = user_name.split('/')[-1]
            access_keys_data = iamclient.list_access_keys(UserName=user_name)
            node.access_keys = len(access_keys_data['AccessKeyMetadata'])
            # logger.debug('Access Key Count for {}: {}'.format(user_name, len(access_keys_data['AccessKeyMetadata'])))

    logger.info('Gathering MFA virtual device information')
    mfa_paginator = iamclient.get_paginator('list_virtual_mfa_devices')
    for page in mfa_paginator.paginate(AssignmentStatus='Assigned'):
        for device in page['VirtualMFADevices']:
            user_arn = device['User']['Arn']
            logger.debug('Found virtual MFA device for {}'.format(user_arn))
            for node in result['nodes']:
                if node.arn == user_arn:
                    node.has_mfa = True
                    break

    logger.info('Gathering MFA physical device information')
    for node in result['nodes']:
        node_resource_name = arns.get_resource(node.arn)
        if node_resource_name.startswith('user/'):
            user_name = node_resource_name.split('/')[-1]
            mfa_devices_response = iamclient.list_mfa_devices(
                UserName=user_name)
            if len(mfa_devices_response['MFADevices']) > 0:
                node.has_mfa = True

    return result
Esempio n. 14
0
def get_secrets_manager_policies(
        session: botocore.session.Session,
        region_allow_list: Optional[List[str]] = None,
        region_deny_list: Optional[List[str]] = None) -> List[Policy]:
    """Using a botocore Session object, return a list of Policy objects representing the resource policies
    of the secrets in AWS Secrets Manager.

    The region allow/deny lists are mutually-exclusive (i.e. at least one of which has the value None) lists of
    allowed/denied regions to pull data from.
    """
    result = []

    # Iterate through all regions of Secrets Manager where possible
    for sm_region in get_regions_to_search(session, 'secretsmanager',
                                           region_allow_list,
                                           region_deny_list):
        try:
            # Grab the ARNs of the secrets in this region
            secret_arns = []
            smclient = session.create_client('secretsmanager',
                                             region_name=sm_region)
            list_secrets_paginator = smclient.get_paginator('list_secrets')
            for page in list_secrets_paginator.paginate():
                if 'SecretList' in page:
                    for entry in page['SecretList']:
                        if 'PrimaryRegion' in entry and entry[
                                'PrimaryRegion'] != sm_region:
                            continue  # skip things we're supposed to find in other regions
                        secret_arns.append(entry['ARN'])

            # Grab resource policies for each secret
            for secret_arn in secret_arns:
                sm_response = smclient.get_resource_policy(SecretId=secret_arn)

                # verify that it is in the response and not None/empty
                if 'ResourcePolicy' in sm_response and sm_response[
                        'ResourcePolicy']:
                    sm_policy_doc = json.loads(sm_response['ResourcePolicy'])
                    result.append(
                        Policy(secret_arn, sm_response['Name'], sm_policy_doc))
                    logger.info(
                        'Storing the resource policy for secret {}'.format(
                            secret_arn))
                else:
                    result.append(
                        Policy(secret_arn, sm_response['Name'], {
                            "Statement": [],
                            "Version": "2012-10-17"
                        }))
                    logger.info(
                        'Secret {} does not have a resource policy, inserting a "stub" policy instead'
                        .format(secret_arn))

        except botocore.exceptions.ClientError as ex:
            logger.info(
                'Unable to search Secrets Manager in region {} for secrets. The region may be disabled, or '
                'the current principal may not be authorized to access the service. '
                'Continuing.'.format(sm_region))
            logger.debug('Exception was: {}'.format(ex))

    return result
    def test_permissions_boundary_with_resource_policy(self):
        boundary_1 = Policy(
            'arn:aws:iam::aws:policy/AssumeJumpRole',
            'AssumeJumpRole',
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Action": "sts:AssumeRole",
                        "Resource": "arn:aws:iam::000000000000:role/JumpRole",
                        "Effect": "Allow"
                    }
                ]
            }
        )

        iam_user_1 = _build_user_with_policy(
            {
                'Version': '2012-10-17',
                'Statement': [{
                    'Effect': 'Allow',
                    'Action': '*',
                    'Resource': '*'
                }]
            },
            'admin_policy',
            'asdf1',
            '1'
        )

        iam_user_1.permissions_boundary = boundary_1

        boundary_2 = Policy(
            'arn:aws:iam::aws:policy/EmptyPolicy',
            'EmptyPolicy',
            {
                "Version": "2012-10-17",
                "Statement": []
            }
        )

        iam_user_2 = _build_user_with_policy(
            {
                'Version': '2012-10-17',
                'Statement': []
            },
            'admin_policy',
            'asdf2',
            '2'
        )

        iam_user_2.permissions_boundary = boundary_2

        trust_doc = {
            'Version': '2012-10-17',
            'Statement': [{
                'Effect': 'Allow',
                'Principal': {
                    'AWS': [
                        'arn:aws:iam::000000000000:user/asdf2',
                        'arn:aws:iam::000000000000:root'
                    ]
                },
                'Action': 'sts:AssumeRole'
            }]
        }

        self.assertTrue(
            local_check_authorization_full(
                iam_user_1,
                'sts:AssumeRole',
                'arn:aws:iam::000000000000:role/JumpRole',
                {},
                trust_doc,
                '000000000000'
            )
        )

        self.assertTrue(
            local_check_authorization_full(
                iam_user_2,
                'sts:AssumeRole',
                'arn:aws:iam::000000000000:role/JumpRole',
                {},
                trust_doc,
                '000000000000'
            )
        )