Example #1
0
def handle_graph(parsed_args) -> int:
    """Processes the arguments for the graph subcommand and executes related tasks"""
    session = _grab_session(parsed_args)

    if parsed_args.create:  # --create
        graph = principalmapper.graphing.graph_actions.create_new_graph(
            session, checker_map.keys(), parsed_args.debug)
        principalmapper.graphing.graph_actions.print_graph_data(graph)
        graph.store_graph_as_json(
            os.path.join(get_storage_root(), graph.metadata['account_id']))

    elif parsed_args.display:  # --display
        graph = principalmapper.graphing.graph_actions.get_existing_graph(
            session, parsed_args.account, parsed_args.debug)
        principalmapper.graphing.graph_actions.print_graph_data(graph)

    elif parsed_args.list:  # --list
        print("Account IDs:")
        print("---")
        storage_root = Path(get_storage_root())
        for direct in storage_root.iterdir():
            print(direct.name)

    elif parsed_args.update_edges:  # --update-edges
        graph = principalmapper.graphing.graph_actions.get_existing_graph(
            session, parsed_args.account, parsed_args.debug)
        graph.edges = principalmapper.graphing.edge_identification.obtain_edges(
            session, checker_map.keys(), graph.nodes, sys.stdout,
            parsed_args.debug)
        principalmapper.graphing.graph_actions.print_graph_data(graph)
        graph.store_graph_as_json(
            os.path.join(get_storage_root(), graph.metadata['account_id']))

    return 0
Example #2
0
def lambda_handler(event, context):

    print(event)
    payload = json.loads(event['body'])
    print(payload)

    bucketName = payload['bucketname']
    s3ObjectName = payload['s3objectname']
    s3ObjectName2 = payload['s3objectname2']

    parser = argparse.ArgumentParser()
    parser.add_argument('--profile', default='default')
    parser.add_argument('--format', default='text', choices=['text', 'json'])

    parsed_args = parser.parse_args()
    session = botocore_tools.get_session(parsed_args.profile)
    graph_obj = graph_actions.create_new_graph(session, checker_map.keys())

    #graph report section
    filePath = LOCAL_STORAGE_PATH + s3ObjectName
    graph_writer.handle_request(graph_obj, filePath, 'svg')
    print(filePath)
    s3util.upload_to_s3(filePath, bucketName, s3ObjectName)

    #analysis report section
    filePath2 = LOCAL_STORAGE_PATH + s3ObjectName2
    reportobj = find_risks.gen_report(graph_obj)
    reportdict = reportobj.as_dictionary()
    with open(filePath2, 'w') as outfile:
        json.dump(reportdict, outfile)
    print(filePath2)
    s3util.upload_to_s3(filePath2, bucketName, s3ObjectName2)
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())
Example #4
0
def main():
    """Body of the script."""
    # Handle input args --profile and --format
    parser = argparse.ArgumentParser()
    parser.add_argument('--profile')
    parser.add_argument('--format', default='text', choices=['text', 'json'])
    parsed_args = parser.parse_args()

    # Generate the graph (such as with `pmapper graph --create`)
    session = botocore_tools.get_session(parsed_args.profile)
    # graph_obj = gathering.create_graph(session, checker_map.keys())  # gets a Graph object without printing info
    graph_obj = graph_actions.create_new_graph(session, checker_map.keys())

    # Print out identified findings (such as with `pmapper analysis`)
    find_risks.gen_findings_and_print(graph_obj, parsed_args.format)
def lambda_handler(event, context):
    parser = argparse.ArgumentParser()
    parser.add_argument('--profile', default='default')
    parser.add_argument('--format', default='text', choices=['text', 'json'])

    #parsed_args = parser.parse_args(["None"])
    parsed_args = parser.parse_args()
    session = botocore_tools.get_session(parsed_args.profile)
    graph_obj = graph_actions.create_new_graph(session, checker_map.keys())

    dateNow = datetime.now()
    unique_outputFile = "output_" + dateNow.strftime("%H-%M-%S-%f")
    s3ObjectName = unique_outputFile + '.png'

    create_signed_URL(s3ObjectName)

    filePath = LOCAL_STORAGE_PATH + s3ObjectName
    graph_writer.handle_request(graph_obj, filePath, 'png')
    uploaded = s3util.upload_to_s3(filePath, BUCKET_NAME, s3ObjectName)
    return uploaded
Example #6
0
def process_arguments(parsed_args: Namespace):
    """Given a namespace object generated from parsing args, perform the appropriate tasks. Returns an int
    matching expectations set by /usr/include/sysexits.h for command-line utilities."""

    if parsed_args.picked_graph_cmd == 'create':
        logger.debug('Called create subcommand of graph')

        # filter the args first
        if parsed_args.account is not None:
            print(
                'Cannot specify offline-mode param `--account` when calling `pmapper graph create`. If you have '
                'credentials for a specific account to graph, you can use those credentials similar to how the '
                'AWS CLI works (environment variables, profiles, EC2 instance metadata). In the case of using '
                'a profile, use the `--profile [PROFILE]` argument before specifying the `graph` subcommand.'
            )
            return 64

        service_list_base = list(checker_map.keys())
        if parsed_args.include_services is not None:
            service_list = [
                x for x in service_list_base
                if x in parsed_args.include_services
            ]
        elif parsed_args.exclude_services is not None:
            service_list = [
                x for x in service_list_base
                if x not in parsed_args.exclude_services
            ]
        else:
            service_list = service_list_base
        logger.debug(
            'Service list after processing args: {}'.format(service_list))

        # need to know account ID to search potential SCPs
        if parsed_args.localstack_endpoint is not None:
            session = botocore_tools.get_session(
                parsed_args.profile,
                {'endpoint_url': parsed_args.localstack_endpoint})
        else:
            session = botocore_tools.get_session(parsed_args.profile)

        scps = None
        if not parsed_args.ignore_orgs:
            if parsed_args.localstack_endpoint is not None:
                stsclient = session.create_client(
                    'sts', endpoint_url=parsed_args.localstack_endpoint)
            else:
                stsclient = session.create_client('sts')
            caller_identity = stsclient.get_caller_identity()
            caller_account = caller_identity['Account']
            logger.debug("Caller Identity: {}".format(caller_identity))

            org_tree_search_dir = Path(get_storage_root())
            org_id_pattern = re.compile(r'/o-\w+')
            for subdir in org_tree_search_dir.iterdir():
                if org_id_pattern.search(str(subdir)) is not None:
                    logger.debug(
                        'Checking {} to see if account {} is a member'.format(
                            str(subdir), caller_account))
                    org_tree = OrganizationTree.create_from_dir(str(subdir))
                    if caller_account in org_tree.accounts:
                        logger.info(
                            'Account {} is a member of Organization {}'.format(
                                caller_account, org_tree.org_id))
                        if caller_account == org_tree.management_account_id:
                            logger.info(
                                'Account {} is the management account, SCPs do not apply'
                                .format(caller_account))
                        else:
                            logger.info(
                                'Identifying and applying SCPs for the graphing process'
                            )
                            scps = query_orgs.produce_scp_list_by_account_id(
                                caller_account, org_tree)
                        break

        if parsed_args.localstack_endpoint is not None:
            full_service_list = ('autoscaling', 'cloudformation', 'codebuild',
                                 'ec2', 'iam', 'kms', 'lambda', 'sagemaker',
                                 's3', 'ssm', 'secretsmanager', 'sns', 'sts',
                                 'sqs')

            client_args_map = {
                x: {
                    'endpoint_url': parsed_args.localstack_endpoint
                }
                for x in full_service_list
            }
        else:
            client_args_map = None

        graph = graph_actions.create_new_graph(session, service_list,
                                               parsed_args.include_regions,
                                               parsed_args.exclude_regions,
                                               scps, client_args_map)
        graph_actions.print_graph_data(graph)
        graph.store_graph_as_json(
            os.path.join(get_storage_root(), graph.metadata['account_id']))

    elif parsed_args.picked_graph_cmd == 'display':
        if parsed_args.account is None:
            session = botocore_tools.get_session(parsed_args.profile)
        else:
            session = None

        graph = graph_actions.get_existing_graph(session, parsed_args.account)
        graph_actions.print_graph_data(graph)

    elif parsed_args.picked_graph_cmd == 'list':
        print("Account IDs:")
        print("---")
        storage_root = Path(get_storage_root())
        account_id_pattern = re.compile(r'\d{12}')
        for direct in storage_root.iterdir():
            if account_id_pattern.search(str(direct)) is not None:
                metadata_file = direct.joinpath(Path('metadata.json'))
                with open(str(metadata_file)) as fd:
                    account_metadata = json.load(fd)
                version = account_metadata['pmapper_version']
                print("{} (PMapper Version {})".format(direct.name, version))

    return 0