A Python script and library for analyzing an AWS account's use of IAM.
Principal Mapper (PMapper) is a script and library for identifying risks in the configuration of AWS Identity and Access Management (IAM) in an AWS account.
PMapper allows users to identify which IAM users and roles have access to certain actions and resources in an AWS account. This is important for ensuring that sensitive resources, such as S3 objects with PII, are isolated.
PMapper creates a graph of an AWS account's IAM users and roles (principals). This graph, composed of nodes and edges, represents the different ways that one principal could access another. When running a query to determine if a principal has access to a certain action/resource, it also checks if the user or role could access other users or roles that have access to that action/resource. This catches scenarios such as when a user doesn't have direct access to an S3 object, but could launch an EC2 instance that has access to the S3 object.
Principal Mapper is built using the
botocore library and Python 3.5+. Python 2 is not supported. Principal Mapper
pydot (available on
graphviz (available on Windows, macOS, and Linux from
Installation from Pip
pip install principalmapper
Installation From Source Code
Clone the repository:
git clone email@example.com:nccgroup/PMapper.git
Then install with Pip:
cd PMapper pip install .
To start, create a graph for an AWS account:
pmapper graph --create
This stores information locally on disk about all the IAM users, roles, groups, and policies in the account. Accounts that are already graphed can be found using:
pmapper graph --list
The account IDs that are printed can be used in other
pmapper subcommands via the
After creating a graph, write queries to learn more about which users and roles can access certain actions or resources.
pmapper argquery --action s3:GetObject --resource arn:aws:s3:::bucket/path/to/object
argquery takes the elements to check for (principal, action, resource, conditions) as arguments of the
--principal is not specified, it runs the query for all IAM users and roles in the account. When
--resource is not specified, it defaults to the wildcard (
query parses a more human-readable input string into a query and returns the results.
pmapper query "who can do s3:GetObject with arn:aws:s3:::bucket/path/to/object"
There are two special queries, presets, available:
privesc: Identify privilege escalation risks.
connected: Identify which principals can access other principals.
These presets are accessible from
argquery. See the following examples:
# Determine if PowerUser can escalate privileges pmapper query "preset privesc user/PowerUser" pmapper argquery --principal user/PowerUser --preset privesc # Find all principals that can escalate privileges pmapper query "preset privesc *" pmapper argquery --principal '*' --preset privesc # Find all principals that PowerUser can access pmapper query "preset connected user/PowerUser *" pmapper argquery --principal user/PowerUser --resource '*' --preset connected # Find all principals that can access PowerUser pmapper query "preset connected * user/PowerUser" pmapper argquery --principal '*' --resource user/PowerUser --preset connected
The Read-Evaluate-Print-Loop (REPL) is a program for running several queries at once. The REPL has four commands:
query: Executes human-readable queries.
argquery: Executes queries with a set of parameters.
help: Prints out information on how to use the REPL.
exit: Exits the REPL (Ctrl+C should also work).
When the REPL is launched, it loads the data for a single graph and executes all queries against that graph. You can launch the repl like so:
Interacting with the REPL is very similar to running multiple queries from the command-line:
repl> query "who can do s3:GetObject with *" ... repl> argquery --principal "*" --preset privesc
PMapper includes a visualization feature, which draws a specified graph. This graph highlights principals with
administrative privileges in blue, and principals that can escalate privileges in red. It supports SVG, PNG, and DOT
file outputs. It uses
graphviz in order to create the image. It can be used like so:
pmapper visualize --filetype png
PMapper provides analysis to identify risks with the configuration in an account. It provides details on the risk, what
impact it could have on the account, which principals are affected, and a recommendation on how to mitigate the risk.
The outputs from
analysis can be in text or JSON format, and can be created with the following command:
pmapper analysis --output-type text
Credentials and Global Parameters
PMapper grabs credentials in the following order:
--profileargument, when specified, is checked first. If specified, PMapper grabs credentials from botocore for that profile name.
- PMapper uses the
botocore.session, which should grab credentials from the environment variables/metadata service/default profile.
For querying, REPL, visualization, and analysis, you can specify the
--account argument with the 12-digit ID of the
account to examine. This cannot be specified along with
--profile. It directs PMapper to use that account
for the command, rather that deriving the account from credentials.
Principal Mapper includes a library that can be used instead of the command-line interface. All functions and methods have type-hints and a small amount of documentation for reference. See example_script.py for an example.
Future major-version revisions (e.g. 1.X.X -> 2.0.0) of Principal Mapper may alter/remove functions/classes/methods. Minor-version revisions (e.g. 1.1.X -> 1.2.0) will not remove existing functions/classes/methods but may add new ones or alter their behaviors.
Exception: All instances of the
debug parameter in all of the functions in this library, which is used by the
dprint function, will eventually be removed as the logging bits are improved. Just keep the
debug parameter out
of your production code.
dprint is gonna be replaced too.
Packages of Interest
Policy. These can be imported straight through
principalmapper.commonwith a single statement:
from principalmapper.common import Graph, Node, Edge
get_existing_graph: grabs a Graph object from disk, based on current botocore session or account ID, from a standard location on-disk.
get_graph_from_disk: grabs a Graph object from disk, user-specified directory.
create_graph: generates Graph objects using a botocore Session object.
checker_map: a dictionary, the keys of which are services that this version of Principal Mapper can get edge data from. This should always be updated with all services that are supported, and
checker_map.keys()can always be passed to
search_authorization_for: performs an expansive search to determine if a principal can make a given AWS API call, or if the principal can access another that does have permission. Returns
QueryResultobjects (defined in
principalmapper.querying.query_result) with information on if the principal is authorized, or if it has to chain through other principals with authorization.
local_check_authorization: determines if a principal can make a given AWS API call, but DOES NOT perform the expansive search of
local_check_authorization_handling_mfa: determines if a principal can make a given AWS API call, DOES NOT perform the expansive search of
search_authorization_for, but DOES manipulate condition keys to test if the AWS API call can be made with or without MFA. Note that you can achieve the same effect by calling
local_check_authorizationand setting the multi-factor auth conditions.
handle_request: creates an image file (PNG/SVG) or graph file (DOT)
gen_findings_and_print: dumps findings in markdown(text)/JSON format to stdout. Wraps around
gen_report, which can be used instead for custom formatting by pulling
Report: a simple object containing metadata about generated findings (account ID, date, version of PMapper).
Finding: a simple object containing data about a risk to the AWS account.
- functions prefixed with
get_: extract a specific chunk of an ARN, like the account ID or region.
- functions prefixed with
get_session: get a botocore Session object based on optional profile parameter.
get_storage_root: returns a path on disk that Principal Mapper will use for storing Graph data by default. Output depends on OS.
Copyright (c) NCC Group and Erik Steringer 2019. This file is part of Principal Mapper. Principal Mapper is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Principal Mapper is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Principal Mapper. If not, see <https://www.gnu.org/licenses/>.
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
|Filename, size||File type||Python version||Upload date||Hashes|
|Filename, size principalmapper-1.0.1.tar.gz (370.3 kB)||File type Source||Python version None||Upload date||Hashes View|