nccgroup / PMapper

A tool for quickly evaluating IAM permissions in AWS.
GNU Affero General Public License v3.0
1.37k stars 169 forks source link

Exception When Policy is Only Used as Permission Boundary #121

Open brandonstevens opened 1 year ago

brandonstevens commented 1 year ago

Describe the bug PMapper throws an exception and exits when attempting to graph an AWS Account that contains an IAM identity that includes a Permission Boundary that has not other usage. i.e. a managed policy is not attached to any identities and only used as a permission boundary.

$  pmapper graph create
2022-11-01 17:29:59+0000 | Obtaining IAM Users/Roles/Groups/Policies in the account.
2022-11-01 17:30:10+0000 | Sorting users, roles, groups, policies, and their relationships.
Traceback (most recent call last):
  File "/usr/local/bin/pmapper", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/site-packages/principalmapper/__main__.py", line 145, in main
    return graph_cli.process_arguments(parsed_args)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/graph_cli.py", line 179, in process_arguments
    graph = graph_actions.create_new_graph(session, service_list, parsed_args.include_regions,
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/graph_actions.py", line 39, in create_new_graph
    return gathering.create_graph(session, service_list, region_allow_list, region_deny_list, scps, client_args_map)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/gathering.py", line 75, in create_graph
    results = get_nodes_groups_and_policies(iamclient)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/gathering.py", line 187, in get_nodes_groups_and_policies
    boundary_policy = _get_policy_by_arn_or_raise(u['PermissionsBoundary']['PermissionsBoundaryArn'],
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/gathering.py", line 1005, in _get_policy_by_arn_or_raise
    raise ValueError('Could not locate policy {}.'.format(arn))
ValueError: Could not locate policy arn:aws:iam::aws:policy/<REDACTED>.

To Reproduce Steps to reproduce the behavior, please include information on suspected users/roles that are the source of the issue when possible:

  1. Create a new IAM User. The user does not need any permissions.
  2. Attach an unused managed-policy as a permission boundary only. When viewing the policy in the Console, under "Policy usage", Permissions should be empty.
  3. Run PMapper

Expected behavior PMapper successfully completes graphing the environment.

Note For testing, I changed https://github.com/nccgroup/PMapper/blob/master/principalmapper/graphing/gathering.py#L187 to no longer raise an error if the policy isn't found in the graph data by swapping the function to _get_policy_by_arn (see below).

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

I don't know what side-effects this may have, but if this is acceptable, happy to create a PR with the change.

Techbrunch commented 9 months ago

I ran into a similar issue except that the error was raised line 184:

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

The problematic policy is attached as a permissions policy to an IAM user.

I used the same workaround as @brandonstevens but ran into another issue (not sure if linked):

# pmapper graph create
2023-09-19 14:57:32+0000 | Obtaining IAM Users/Roles/Groups/Policies in the account.
2023-09-19 14:57:56+0000 | Sorting users, roles, groups, policies, and their relationships.
2023-09-19 14:57:56+0000 | Obtaining Access Keys data for IAM users
2023-09-19 14:58:40+0000 | Gathering MFA virtual device information
2023-09-19 14:58:40+0000 | Gathering MFA physical device information
2023-09-19 14:59:05+0000 | Determining which principals have administrative privileges
Traceback (most recent call last):
  File "/usr/local/bin/pmapper", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/site-packages/principalmapper/__main__.py", line 145, in main
    return graph_cli.process_arguments(parsed_args)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/graph_cli.py", line 179, in process_arguments
    graph = graph_actions.create_new_graph(session, service_list, parsed_args.include_regions,
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/graph_actions.py", line 39, in create_new_graph
    return gathering.create_graph(session, service_list, region_allow_list, region_deny_list, scps, client_args_map)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/gathering.py", line 81, in create_graph
    update_admin_status(nodes_result, scps)
  File "/usr/local/lib/python3.8/site-packages/principalmapper/graphing/gathering.py", line 782, in update_admin_status
    if query_interface.local_check_authorization_handling_mfa(node, action, node.arn, {},
  File "/usr/local/lib/python3.8/site-packages/principalmapper/querying/query_interface.py", line 208, in local_check_authorization_handling_mfa
    if local_check_authorization_full(principal, action_to_check, resource_to_check, condition_keys_to_check, resource_policy, resource_owner, service_control_policy_groups, session_policy):
  File "/usr/local/lib/python3.8/site-packages/principalmapper/querying/query_interface.py", line 306, in local_check_authorization_full
    if policy_has_matching_statement(policy, 'Deny', action_to_check, resource_to_check, prepped_condition_keys):
  File "/usr/local/lib/python3.8/site-packages/principalmapper/querying/local_policy_simulation.py", line 68, in policy_has_matching_statement
    for statement in _listify_dictionary(base_obj['Statement']):
TypeError: 'NoneType' object is not subscriptable