def get_expanded_policy(policy): """ Given a policy, expand the * Actions in IAM policy files to improve readability :param policy: dictionary containing valid AWS IAM Policy :return: """ modified_policy = copy.deepcopy(policy) if isinstance(modified_policy["Statement"], dict): requested_actions = get_actions_from_statement( modified_policy["Statement"]) expanded_actions = determine_actions_to_expand(requested_actions) if "NotAction" in modified_policy["Statement"]: if isinstance(modified_policy["Statement"]["NotAction"], list): modified_policy["Statement"]["NotAction"].clear() modified_policy["Statement"]["NotAction"].extend( expanded_actions) elif isinstance(modified_policy["Statement"]["NotAction"], str): modified_policy["Statement"]["NotAction"] = [] logger.warning( "NotAction is in the statement. Policy Sentry will expand any wildcard actions " "that are in the NotAction list, but it will not factor the NotAction actions into any analysis about " "whether or not the actions are allowed by the policy. " "If you are concerned about this, please review this specific policy manually." ) elif "Action" in modified_policy["Statement"]: if isinstance(modified_policy["Statement"]["Action"], list): modified_policy["Statement"]["Action"].clear() modified_policy["Statement"]["Action"].extend(expanded_actions) elif isinstance(modified_policy["Statement"]["Action"], str): modified_policy["Statement"]["Action"] = [] # Otherwise it will be a list of Sids elif isinstance(modified_policy["Statement"], list): for statement in modified_policy["Statement"]: requested_actions = get_actions_from_statement(statement) expanded_actions = determine_actions_to_expand(requested_actions) if "NotAction" in statement: if isinstance(statement["NotAction"], list): statement["NotAction"].clear() statement["NotAction"].extend(expanded_actions) elif isinstance(statement["NotAction"], str): statement["NotAction"] = [] logger.warning( "NotAction is in the statement. Policy Sentry will expand any wildcard actions " "that are in the NotAction list, but it will not factor the NotAction actions into any analysis " "about whether or not the actions are allowed by the policy." "If you are concerned about this, please review this specific policy manually." ) elif "Action" in statement: if isinstance(statement["Action"], list): statement["Action"].clear() elif isinstance(statement["Action"], str): statement["Action"] = [] statement["Action"].extend(expanded_actions) else: logger.critical( "Unknown error: The 'Statement' is neither a dict nor a list") return modified_policy
def analyze_statement_by_access_level(statement_json, access_level): """ Determine if a statement has any actions with a given access level. :param statement_json: a dictionary representing a statement from an AWS JSON policy :param access_level: The access level - either 'Read', 'List', 'Write', 'Tagging', or 'Permissions management' """ requested_actions = get_actions_from_statement(statement_json) expanded_actions = determine_actions_to_expand(requested_actions) actions_by_level = remove_actions_not_matching_access_level( expanded_actions, access_level ) return actions_by_level
def analyze_statement_by_access_level(db_session, statement_json, access_level): """ Determine if a statement has any actions with a given access level. :param db_session: SQLAlchemy database session :param statement_json: a dictionary representing a statement from an AWS JSON policy :param access_level: The normalized access level - either 'read', 'list', 'write', 'tagging', or 'permissions-management' """ requested_actions = get_actions_from_statement(statement_json) expanded_actions = determine_actions_to_expand(db_session, requested_actions) actions_by_level = remove_actions_not_matching_access_level( db_session, expanded_actions, access_level) return actions_by_level