def analyze_policy_file(policy_file, account_id, from_audit_file, finding_type, excluded_role_patterns): """ Given a policy file, determine risky actions based on a separate file containing a list of actions. If it matches a policy exclusion pattern from the report-config.yml file, that policy file will be skipped. """ # FIXME: Rename "role_exclusion_pattern" to "policy_exclusion_pattern" requested_actions = get_actions_from_json_policy_file(policy_file) expanded_actions = determine_actions_to_expand(requested_actions) finding = {} policy_findings = {} policy_name = policy_file.rsplit(".", 1)[0] # after the extension policy_name_split = str.split(policy_name, '/') # if there are multiple folders deep pick `file` from `path/to/file` policy_name = policy_name_split[-1:][0] # If the policy name matches excluded role patterns, skip it reg_list = map(re.compile, excluded_role_patterns) if any(regex.match(policy_name) for regex in reg_list): return False else: actions_list = determine_risky_actions( expanded_actions, from_audit_file) actions_list.sort() # sort in alphabetical order actions_list = list(dict.fromkeys(actions_list)) # remove duplicates if actions_list: finding[finding_type] = copy.deepcopy(actions_list) # Store the account ID finding['account_id'] = account_id policy_findings[policy_name] = copy.deepcopy(finding) else: # Just store the account ID finding['account_id'] = account_id return policy_findings
def analyze_policy_directory(policy_directory, account_id, from_audit_file, finding_type, excluded_role_patterns): """ Audits a directory of policy JSON files. :param policy_directory: :param db_session: :param from_audit_file: :param findings_obj: Findings object :return: policy_findings: A dictionary of policy names as keys. The values for those are a list of actions. Like this: credentials_exposure_findings = [ { "PolicyName": [ "ecr:GetAuthorizationToken" ] }, { "PolicyName2": [ "redshift:getclustercredentials" ] } ] """ policy_file_list = list_files_in_directory(policy_directory) policy_findings = {} finding = {} actions_list = [] requested_actions = [] expanded_actions = [] for policy_file in policy_file_list: actions_list.clear() requested_actions.clear() expanded_actions.clear() this_file = policy_directory + '/' + policy_file policy_name = policy_file.rsplit(".", 1)[0] # If the policy name matches excluded role patterns, skip it reg_list = map(re.compile, excluded_role_patterns) if any(regex.match(policy_name) for regex in reg_list): continue requested_actions = get_actions_from_json_policy_file(this_file) expanded_actions = determine_actions_to_expand(requested_actions) actions_list = determine_risky_actions( expanded_actions, from_audit_file) actions_list.sort() # sort in alphabetical order actions_list = list(dict.fromkeys(actions_list)) # remove duplicates # try: if actions_list: finding[finding_type] = copy.deepcopy(actions_list) finding['account_id'] = account_id policy_findings[policy_name] = copy.deepcopy(finding) # Store the account ID else: finding['account_id'] = account_id # print(finding['account_id']) # except KeyError as k_e: # print(k_e) # continue return policy_findings
def test_get_actions_from_policy_file_with_wildcards(self): """test_get_actions_from_policy_file_with_wildcards: Verify that we can read the actions from a file, even if it contains wildcards""" policy_file_path = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir + '/examples/analyze/wildcards.json')) requested_actions = get_actions_from_json_policy_file(policy_file_path) print(requested_actions) desired_actions_list = ['ecr:*', 's3:*'] self.maxDiff = None self.assertListEqual(requested_actions, desired_actions_list)
def analyze_by_access_level(policy_file, db_session, access_level): """ Determine if a policy has any actions with a given access level. This is particularly useful when determining who has 'Permissions management' level access """ requested_actions = get_actions_from_json_policy_file(policy_file) expanded_actions = determine_actions_to_expand(requested_actions) actions_by_level = get_actions_by_access_level(db_session, expanded_actions, access_level) # if not actions_by_level: # pass # else: # policy_path_elements = policy_file.split('/') # # policy_name = policy_path_elements[-1] # # print("\nPolicy: " + policy_name) # # pp = pprint.PrettyPrinter(indent=4) # # pp.pprint(levels) return actions_by_level
def analyze(policy_file, db_session, from_access_level, from_audit_file): requested_actions = get_actions_from_json_policy_file(policy_file) expanded_actions = determine_actions_to_expand(requested_actions) if from_access_level: levels = get_actions_by_access_level(db_session, expanded_actions, from_access_level) if not levels: pass else: policy_path_elements = policy_file.split('/') policy_name = policy_path_elements[-1] print("\nPolicy: " + policy_name) pp = pprint.PrettyPrinter(indent=4) pp.pprint(levels) else: print("These are the expanded actions") print(expanded_actions) determine_risky_actions(expanded_actions, from_audit_file)
def test_get_actions_from_policy_file_with_explicit_actions(self): """test_get_actions_from_policy_file_with_explicit_actions: Verify that we can get a list of actions from a file when it contains specific actions""" policy_file_path = os.path.abspath( os.path.join( os.path.dirname(__file__), os.path.pardir + '/examples/analyze/explicit-actions.json')) requested_actions = get_actions_from_json_policy_file(policy_file_path) # print(requested_actions) desired_actions_list = [ 'ecr:batchchecklayeravailability', 'ecr:batchgetimage', 'ecr:completelayerupload', 'ecr:describeimages', 'ecr:describerepositories', 'ecr:getauthorizationtoken', 'ecr:getdownloadurlforlayer', 'ecr:getrepositorypolicy', 'ecr:initiatelayerupload', 'ecr:listimages', 'ecr:putimage', 'ecr:uploadlayerpart', 'iam:createaccesskey', 'iam:deleteaccesskey', 'iam:listaccesskeys', 'iam:updateaccesskey' ] self.maxDiff = None self.assertListEqual(requested_actions, desired_actions_list)