def get_rendered_policy(self, minimize=None): """ Get the JSON rendered policy :param minimize: Reduce the character count of policies without creating overlap with other action names :rtype: dict """ statements = [] # Only set the actions to lowercase if minimize is provided all_actions = get_all_actions(lowercase=True) # render the policy for sid in self.sids: actions = self.sids[sid]["actions"] if len(actions) == 0: logger.debug(f"No actions for sid {sid}") continue if minimize is not None and isinstance(minimize, int): logger.debug("Minimizing statements...") actions = minimize_statement_actions(actions, all_actions, minchars=minimize) logger.debug(f"Adding statement with SID {sid}") logger.debug(f"{sid} SID has the actions: {actions}") logger.debug( f"{sid} SID has the resources: {self.sids[sid]['arn']}") statements.append({ "Sid": sid, "Effect": "Allow", "Action": actions, "Resource": self.sids[sid]["arn"], }) policy = {"Version": POLICY_LANGUAGE_VERSION, "Statement": statements} return policy
def print_policy(arn_dict_with_actions_and_resources, db_session, minimize=None): """ Prints the least privilege policy """ statement = [] all_actions = get_all_actions(db_session) for sid in arn_dict_with_actions_and_resources: actions = arn_dict_with_actions_and_resources[sid]['actions'] if minimize is not None and isinstance(minimize, int): actions = minimize_statement_actions(actions, all_actions, minchars=minimize) statement.append({ "Sid": arn_dict_with_actions_and_resources[sid]['name'], "Effect": "Allow", "Action": actions, "Resource": arn_dict_with_actions_and_resources[sid]['arns'] }) policy = {"Version": POLICY_LANGUAGE_VERSION, "Statement": statement} return policy
def get_rendered_policy(self, db_session, minimize=None): """ Get the JSON rendered policy :param db_session: SQLAlchemy database session :param minimize: Reduce the character count of policies without creating overlap with other action names :rtype: dict """ statements = [] # Only set the actions to lowercase if minimize is provided all_actions = get_all_actions(db_session, lowercase=True) # render the policy for sid in self.sids: actions = self.sids[sid]["actions"] if len(actions) == 0: continue if minimize is not None and isinstance(minimize, int): actions = minimize_statement_actions(actions, all_actions, minchars=minimize) statements.append({ "Sid": sid, "Effect": "Allow", "Action": actions, "Resource": self.sids[sid]["arn"], }) policy = {"Version": POLICY_LANGUAGE_VERSION, "Statement": statements} return policy
def test_minimize_statement_actions(self): actions_to_minimize = [ "kms:creategrant", "kms:createcustomkeystore", "ec2:authorizesecuritygroupegress", "ec2:authorizesecuritygroupingress" ] desired_result = ['ec2:authorizes*', 'kms:createc*', 'kms:createg*'] all_actions = get_all_actions(db_session) minchars = None self.maxDiff = None # minimized_actions_list = minimize_statement_actions(desired_actions, all_actions, minchars) self.assertListEqual( sorted( minimize_statement_actions(actions_to_minimize, all_actions, minchars)), sorted(desired_result))
def get_rendered_policy(self, minimize=None): """ Get the JSON rendered policy Arguments: minimize: Reduce the character count of policies without creating overlap with other action names Returns: Dictionary: The IAM Policy JSON """ statements = [] # Only set the actions to lowercase if minimize is provided all_actions = get_all_actions(lowercase=True) # render the policy for sid in self.sids: temp_actions = self.sids[sid]["actions"] if len(temp_actions) == 0: logger.debug(f"No actions for sid {sid}") continue actions = [] if self.exclude_actions: for temp_action in temp_actions: if temp_action.lower() in self.exclude_actions: logger.debug(f"\tExcluded action: {temp_action}") else: if temp_action not in actions: actions.append(temp_action) else: actions = temp_actions # temp_actions.clear() if minimize is not None and isinstance(minimize, int): logger.debug("Minimizing statements...") actions = minimize_statement_actions(actions, all_actions, minchars=minimize) logger.debug(f"Adding statement with SID {sid}") logger.debug(f"{sid} SID has the actions: {actions}") logger.debug( f"{sid} SID has the resources: {self.sids[sid]['arn']}") statements.append({ "Sid": sid, "Effect": "Allow", "Action": actions, "Resource": self.sids[sid]["arn"], }) policy = {"Version": POLICY_LANGUAGE_VERSION, "Statement": statements} return policy
def test_minimize_statement_actions_funky_case(self): actions_to_minimize = [ "kms:creategrant", "kms:createcustomkeystore", "ec2:authorizesecuritygroupegress", "ec2:authorizesecuritygroupingress", ] desired_result = ["ec2:authorizes*", "kms:createc*", "kms:createg*"] all_actions = get_all_actions(lowercase=True) minchars = None self.maxDiff = None # minimized_actions_list = minimize_statement_actions(desired_actions, all_actions, minchars) self.assertListEqual( sorted( minimize_statement_actions(actions_to_minimize, all_actions, minchars)), sorted(desired_result), )
def test_minimize_statement_actions(self): actions_to_minimize = [ "kms:CreateGrant", "kms:CreateCustomKeyStore", "ec2:AuthorizeSecurityGroupEgress", "ec2:AuthorizeSecurityGroupIngress", ] desired_result = ["ec2:authorizes*", "kms:createc*", "kms:createg*"] all_actions = get_all_actions(lowercase=True) minchars = None self.maxDiff = None # minimized_actions_list = minimize_statement_actions(desired_actions, all_actions, minchars) self.assertListEqual( sorted( minimize_statement_actions(actions_to_minimize, all_actions, minchars)), sorted(desired_result), )
def get_all_action_links(): """ Gets a huge list of the links to all AWS IAM actions. This is meant for use by Cloudsplaining. :return: A dictionary of all actions present in the database, with the values being the API documentation links. """ all_actions = get_all_actions() results = {} for action in all_actions: try: service_prefix, action_name = action.split(":") except ValueError as v_e: logger.debug(f"{v_e} - for action {action}") continue link = get_api_documentation_link_for_action(service_prefix, action_name) result = {action: link} results.update(result) return results
def expand(action): """ expand the action wildcards into a full action Arguments: action: An action in the form with a wildcard - like s3:Get*, or s3:L* Returns: List: A list of all the expanded actions (like actions matching s3:Get*) """ all_actions = get_all_actions() if isinstance(action, list): expanded_actions = [] for item in action: expanded_actions.extend(expand(item)) return expanded_actions if "*" in action: expanded = [ expanded_action # for expanded_action in all_permissions for expanded_action in all_actions if fnmatch.fnmatchcase(expanded_action.lower(), action.lower()) ] # if we get a wildcard for a tech we've never heard of, just return the # wildcard if not expanded: logger.debug( "ERROR: The action %s references a wildcard for an unknown resource.", action, ) return [action] return expanded return [action]
def expand(action, db_session): """ expand the action wildcards into a full action :param action: An action in the form with a wildcard - like s3:Get*, or s3:L* :param db_session: SQLAlchemy database session object :return: A list of all the expanded actions (like actions matching s3:Get*) :rtype: list """ all_actions = get_all_actions(db_session) if isinstance(action, list): expanded_actions = [] for item in action: expanded_actions.extend(expand(item, db_session)) return expanded_actions if "*" in action: expanded = [ expanded_action.lower() # for expanded_action in all_permissions for expanded_action in all_actions if fnmatch.fnmatchcase(expanded_action.lower(), action.lower()) ] # if we get a wildcard for a tech we've never heard of, just return the # wildcard if not expanded: logger.warning( "ERROR: The action %s references a wildcard for an unknown resource.", action, ) return [action.lower()] return expanded return [action.lower()]
def setUp(self) -> None: all_actions = get_all_actions() self.all_actions = list(all_actions) self.all_actions.sort()
def test_get_all_actions(self): result = get_all_actions() print("Total count of unique IAM actions:", len(result)) self.assertGreater(len(result), 7000)
def get_rendered_policy(self, minimize=None): """ Get the JSON rendered policy Arguments: minimize: Reduce the character count of policies without creating overlap with other action names Returns: Dictionary: The IAM Policy JSON """ statements = [] # Only set the actions to lowercase if minimize is provided all_actions = get_all_actions(lowercase=True) # render the policy sids_to_be_changed = [] for sid in self.sids: temp_actions = self.sids[sid]["actions"] if len(temp_actions) == 0: logger.debug(f"No actions for sid {sid}") continue actions = [] if self.exclude_actions: for temp_action in temp_actions: if temp_action.lower() in self.exclude_actions: logger.debug(f"\tExcluded action: {temp_action}") else: if temp_action not in actions: actions.append(temp_action) else: actions = temp_actions # temp_actions.clear() match_found = False if minimize is not None and isinstance(minimize, int): logger.debug("Minimizing statements...") actions = minimize_statement_actions(actions, all_actions, minchars=minimize) # searching in the existing statements # further minimizing the the output for stmt in statements: if stmt["Resource"] == self.sids[sid]["arn"]: stmt["Action"].extend(actions) match_found = True sids_to_be_changed.append(stmt["Sid"]) break logger.debug(f"Adding statement with SID {sid}") logger.debug(f"{sid} SID has the actions: {actions}") logger.debug( f"{sid} SID has the resources: {self.sids[sid]['arn']}") if not match_found: statements.append({ "Sid": sid, "Effect": "Allow", "Action": actions, "Resource": self.sids[sid]["arn"], }) if sids_to_be_changed: for stmt in statements: if stmt['Sid'] in sids_to_be_changed: arn_details = parse_arn(stmt['Resource'][0]) resource_path = arn_details.get("resource_path") resource_sid_segment = strip_special_characters( f"{arn_details['resource']}{resource_path}") stmt['Sid'] = create_policy_sid_namespace( arn_details['service'], "Mult", resource_sid_segment) policy = {"Version": POLICY_LANGUAGE_VERSION, "Statement": statements} return policy
#!/usr/bin/env python from policy_sentry.querying.all import get_all_actions if __name__ == '__main__': all_actions = get_all_actions() # returns a set all_actions = list(all_actions) # convert to list all_actions.sort() # sort in alphabetical order print(all_actions) # print """ Output: Every IAM action available across all services, without duplicates """
#!/usr/bin/env python from policy_sentry.shared.database import connect_db from policy_sentry.querying.all import get_all_actions if __name__ == '__main__': db_session = connect_db('bundled') all_actions = get_all_actions(db_session) print(all_actions) """ Output: Every IAM action available across all services, without duplicates """
from policy_sentry.querying.all import get_all_actions from cloudsplaining.shared.utils import ( remove_read_level_actions, remove_wildcard_only_actions, ) from cloudsplaining.shared.exclusions import DEFAULT_EXCLUSIONS, Exclusions # Copyright (c) 2020, salesforce.com, inc. # All rights reserved. # Licensed under the BSD 3-Clause license. # For full license text, see the LICENSE file in the repo root # or https://opensource.org/licenses/BSD-3-Clause logger = logging.getLogger(__name__) logging.getLogger("policy_sentry").setLevel(logging.WARNING) ALL_ACTIONS = get_all_actions() # pylint: disable=too-many-instance-attributes class StatementDetail: """ Analyzes individual statements within a policy """ def __init__(self, statement: Dict[str, Any], flag_conditional_statements: bool = False, flag_resource_arn_statements: bool = False) -> None: self.json = statement self.statement = statement self.effect = statement["Effect"] self.condition = statement.get("Condition", None)
get_actions_matching_arn, ) from policy_sentry.querying.all import get_all_actions from cloudsplaining.shared.utils import ( remove_read_level_actions, remove_wildcard_only_actions, ) # Copyright (c) 2020, salesforce.com, inc. # All rights reserved. # Licensed under the BSD 3-Clause license. # For full license text, see the LICENSE file in the repo root # or https://opensource.org/licenses/BSD-3-Clause logger = logging.getLogger(__name__) all_actions = get_all_actions() # pylint: disable=too-many-instance-attributes class StatementDetail: """ Analyzes individual statements within a policy """ def __init__(self, statement): self.json = statement self.statement = statement self.effect = statement["Effect"] self.resources = self._resources() self.actions = self._actions() self.not_action = self._not_action()