def get_actions_that_support_wildcard_arns_only(service_prefix): """ Get a list of actions that do not support restricting the action to resource ARNs. Set service to "all" to get a list of actions across all services. :param service_prefix: A single AWS service prefix, like `s3` or `kms` :return: A list of actions """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for some_action in service_prefix_data["privileges"]: if len(some_action["resource_types"]) == 1: if some_action["resource_types"][0]["resource_type"] == "": results.append( f"{some_prefix}:{some_action['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for some_action in service_prefix_data["privileges"]: if len(some_action["resource_types"]) == 1: for resource_type in some_action["resource_types"]: if resource_type["resource_type"] == "": results.append( f"{service_prefix}:{some_action['privilege']}") return results
def get_actions_matching_condition_key(service_prefix, condition_key): """ Get a list of actions under a service that allow the use of a specified condition key :param service_prefix: A single AWS service prefix :param condition_key: The condition key to look for. :return: A list of actions """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for some_action in service_prefix_data["privileges"]: for some_resource_type in some_action["resource_types"]: if condition_key in some_resource_type["condition_keys"]: results.append( f"{some_prefix}:{some_action['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for some_action in service_prefix_data["privileges"]: for some_resource_type in some_action["resource_types"]: if condition_key in some_resource_type["condition_keys"]: results.append( f"{service_prefix}:{some_action['privilege']}") return results
def get_actions_with_access_level(service_prefix, access_level): """ Get a list of actions in a service under different access levels. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` access_level: An access level as it is written in the database, such as 'Read', 'Write', 'List', 'Permisssions management', or 'Tagging' Returns: List: A list of actions with that access level and service prefix """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data["access_level"] == access_level: results.append(f"{some_prefix}:{action_data['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data["access_level"] == access_level: results.append(f"{service_prefix}:{action_data['privilege']}") return results
def get_actions_at_access_level_that_support_wildcard_arns_only( service_prefix, access_level): """ Get a list of actions at an access level that do not support restricting the action to resource ARNs. Set service to "all" to get a list of actions across all services. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` access_level: An access level as it is written in the database, such as 'Read', 'Write', 'List', 'Permisssions management', or 'Tagging' Returns: List: A list of actions at that access level that do not support resource ARN constraints """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if len(action_data["resource_types"]) == 1: if (action_data["access_level"] == access_level and action_data["resource_types"].get("")): results.append( f"{some_prefix}:{action_data['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if len(action_data["resource_types"]) == 1: if (action_data["access_level"] == access_level and action_data["resource_types"].get("")): results.append( f"{service_prefix}:{action_data['privilege']}") return results
def get_actions_matching_condition_key(service_prefix, condition_key): """ Get a list of actions under a service that allow the use of a specified condition key Arguments: service_prefix: A single AWS service prefix condition_key: The condition key to look for. Returns: List: A list of actions """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): for resource_name, resource_data in action_data[ "resource_types"].items(): if condition_key in resource_data["condition_keys"]: results.append( f"{service_prefix}:{action_data['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): for resource_name, resource_data in action_data[ "resource_types"].items(): if condition_key in resource_data["condition_keys"]: results.append( f"{service_prefix}:{action_data['privilege']}") return results
def get_actions_that_support_wildcard_arns_only(service_prefix): """ Get a list of actions that do not support restricting the action to resource ARNs. Set service to "all" to get a list of actions across all services. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` Returns: List: A list of actions that do not support resource ARN constraints """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if len(action_data["resource_types"].keys()) == 1: for resource_type in action_data["resource_types"]: if resource_type == '': results.append(f"{service_prefix}:{action_name}") else: service_prefix_data = get_service_prefix_data(service_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if len(action_data["resource_types"].keys()) == 1: for resource_type in action_data["resource_types"]: if resource_type == '': results.append(f"{service_prefix}:{action_name}") return results
def get_actions_with_arn_type_and_access_level(service_prefix, resource_type_name, access_level): """ Get a list of actions in a service under different access levels, specific to an ARN format. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` resource_type_name: The ARN type name, like `bucket` or `key` access_level: Access level like "Read" or "List" or "Permissions management" Return: List: A list of actions that have that ARN type and Access level """ service_prefix_data = get_service_prefix_data(service_prefix) results = [] if resource_type_name == '*': return get_actions_at_access_level_that_support_wildcard_arns_only( service_prefix, access_level) if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data["access_level"] == access_level: for resource_name, resource_data in action_data[ "resource_types"].items(): this_resource_type = resource_data[ "resource_type"].strip("*") if this_resource_type.lower( ) == resource_type_name.lower(): results.append( f"{service_prefix}:{action_data['privilege']}") break else: for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data["access_level"] == access_level: for resource_name, resource_data in action_data[ "resource_types"].items(): this_resource_type = resource_data["resource_type"].strip( "*") if this_resource_type.lower() == resource_type_name.lower( ): results.append( f"{service_prefix}:{action_data['privilege']}") break return results
def update_database_by_matching_compliance_names_with_iam_names( self, db_session, transformed_scraping_database): """ The names of AWS services in the compliance pages vary; let's change the names of those services to directly match the names of the services as listed on the AWS IAM pages. """ for standard in self.standard_names(db_session): # The service name in IAM-land iam_service_names = {} for service_prefix in ALL_SERVICE_PREFIXES: iam_service_names[service_prefix] = get_service_prefix_data( service_prefix)["service_name"] # The service name in compliance land compliance_service_names = ( transformed_scraping_database. get_service_names_matching_compliance_standard( db_session, standard)) for iam_service_prefix in list(iam_service_names.keys()): iam_name = iam_service_names[iam_service_prefix] compliance_names = list(compliance_service_names.keys()) if iam_name in compliance_names: self.update_compliance_status( db_session=db_session, service_prefix= iam_service_prefix, # this is the IAM prefix compliance_standard=standard, status="true", )
def get_actions_matching_arn(arn): """ Given a user-supplied ARN, get a list of all actions that correspond to that ARN. Arguments: arn: A user-supplied arn Returns: List: A list of all actions that can match it. """ raw_arns = get_matching_raw_arns(arn) results = [] for raw_arn in raw_arns: resource_type_name = get_resource_type_name_with_raw_arn(raw_arn) service_prefix = get_service_from_arn(raw_arn) service_prefix_data = get_service_prefix_data(service_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): # for some_action in service_prefix_data["privileges"]: for resource_name, resource_data in action_data[ "resource_types"].items(): this_resource_type = resource_data["resource_type"].strip("*") if this_resource_type.lower() == resource_type_name.lower(): results.append( f"{service_prefix}:{action_data['privilege']}") results = list(dict.fromkeys(results)) results.sort() return results
def get_all_actions(lowercase=False): """ Gets a huge list of all IAM actions. This is used as part of the policyuniverse approach to minimizing IAM Policies to meet AWS-mandated character limits on policies. :param lowercase: Set to true to have the list of actions be in all lowercase strings. :return: A list of all actions present in the database. """ all_actions = set() all_service_prefixes = get_all_service_prefixes() for service_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(service_prefix) for action_name in service_prefix_data["privileges"]: if lowercase: all_actions.add( f"{service_prefix}:{action_name.lower()}" ) else: all_actions.add( f"{service_prefix}:{action_name}" ) # results = list(set(results)) # results.sort() return all_actions
def get_service_name_matching_iam_service_prefix(iam_service_prefix): if iam_definition.get(iam_service_prefix): service_name = get_service_prefix_data( iam_service_prefix)["service_name"] return service_name else: return None
def create_empty_compliance_database(db_session): """ Fill in the compliance database table with the service prefix (ex: s3) and the Service name (Simple Storage Service) and set all the values to blank strings """ for service_prefix in ALL_SERVICE_PREFIXES: name = get_service_prefix_data(service_prefix)["service_name"] db_session.add( ComplianceTable( service_prefix=service_prefix, name=name, SOC="", PCI="", ISO="", FedRAMP_High="", FedRAMP_Moderate="", DoDCCSRG_IL2_EW="", DoDCCSRG_IL2_GC="", DoDCCSRG_IL4_GC="", DoDCCSRG_IL5_GC="", HIPAA="", HITRUST="", IRAP="", OSPAR="", FINMA="", ) ) db_session.commit()
def get_actions_with_arn_type_and_access_level(service_prefix, resource_type_name, access_level): """ Get a list of actions in a service under different access levels, specific to an ARN format. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` resource_type_name: The ARN type name, like `bucket` or `key` access_level: Access level like "Read" or "List" or "Permissions management" Return: List: A list of actions that have that ARN type and Access level """ service_prefix_data = get_service_prefix_data(service_prefix) results = [] for some_action in service_prefix_data["privileges"]: if some_action["access_level"] == access_level: for some_resource_type in some_action["resource_types"]: this_resource_type = some_resource_type["resource_type"].strip( "*") if this_resource_type.lower() == resource_type_name.lower(): results.append( f"{service_prefix}:{some_action['privilege']}") break return results
def get_action_data(service, action_name): """ Get details about an IAM Action in JSON format. Arguments: service: An AWS service prefix, like `s3` or `kms`. Case insensitive. action_name: The name of an AWS IAM action, like `GetObject`. To get data about all actions in a service, specify "*". Case insensitive. Returns: List: A dictionary containing metadata about an IAM Action. """ results = [] action_data_results = {} try: service_info = get_service_prefix_data(service) for privilege_info in service_info["privileges"]: # Get the baseline conditions and dependent actions condition_keys = [] dependent_actions = [] rows = [] if action_name == "*": rows = privilege_info["resource_types"] else: for resource_type_entry in privilege_info["resource_types"]: if privilege_info["privilege"].lower( ) == action_name.lower(): rows.append(resource_type_entry) # for resource_type_entry in privilege_info["resource_types"]: for row in rows: # Set default value for if no other matches are found resource_arn_format = "*" # Get the dependent actions if row["dependent_actions"]: dependent_actions.extend(row["dependent_actions"]) # Get the condition keys for service_resource in service_info["resources"]: if row["resource_type"] == "": continue if row["resource_type"].strip( "*") == service_resource["resource"]: resource_arn_format = service_resource.get("arn", "*") condition_keys = service_resource.get("condition_keys") break temp_dict = { "action": f"{service_info['prefix']}:{privilege_info['privilege']}", "description": privilege_info["description"], "access_level": privilege_info["access_level"], "resource_arn_format": resource_arn_format, "condition_keys": condition_keys, "dependent_actions": dependent_actions, } results.append(temp_dict) action_data_results[service] = results except TypeError as t_e: logger.debug(t_e) # if results: return action_data_results
def get_actions_matching_arn_type(service_prefix, resource_type_name): """ Get a list of actions in a service specific to ARN type. Arguments: service_prefix: A single AWS service prefix, like `s3` or `kms` resource_type_name: The ARN type name, like `bucket` or `key` Return: List: A list of actions that have that ARN type """ if resource_type_name == '*': return get_actions_that_support_wildcard_arns_only(service_prefix) service_prefix_data = get_service_prefix_data(service_prefix) results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): for resource_name, resource_data in action_data[ "resource_types"].items(): this_resource_type = resource_data["resource_type"].strip( "*") if this_resource_type.lower() == resource_type_name.lower( ): results.append( f"{service_prefix}:{action_data['privilege']}") break else: for action_name, action_data in service_prefix_data[ "privileges"].items(): for resource_name, resource_data in action_data[ "resource_types"].items(): this_resource_type = resource_data["resource_type"].strip("*") if this_resource_type.lower() == resource_type_name.lower(): results.append( f"{service_prefix}:{action_data['privilege']}") break return results
def test_get_service_prefix_data(self): result = get_service_prefix_data("cloud9") desired_output_schema = Schema({ "service_name": "AWS Cloud9", "prefix": "cloud9", "privileges": dict, "resources": dict, "conditions": dict }) valid_output = check(desired_output_schema, result) # print(json.dumps(result, indent=4)) self.assertTrue(valid_output)
def get_condition_keys_for_service(service_prefix): """ Get a list of available conditions per AWS service Arguments: service_prefix: An AWS service prefix, like `s3` or `kms` Returns: List: A list of condition keys """ service_prefix_data = get_service_prefix_data(service_prefix) results = list(dict.fromkeys(service_prefix_data["conditions"].keys())) return results
def get_actions_with_access_level(service_prefix, access_level): """ Get a list of actions in a service under different access levels. :param service_prefix: A single AWS service prefix, like `s3` or `kms` :param access_level: An access level as it is written in the database, such as 'Read', 'Write', 'List', 'Permisssions management', or 'Tagging' :return: A list of actions """ results = [] if service_prefix == "all": for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for some_action in service_prefix_data["privileges"]: if some_action["access_level"] == access_level: results.append(f"{some_prefix}:{some_action['privilege']}") else: service_prefix_data = get_service_prefix_data(service_prefix) for some_action in service_prefix_data["privileges"]: if some_action["access_level"] == access_level: results.append(f"{service_prefix}:{some_action['privilege']}") return results
def get_actions_for_service(service_prefix): """ Get a list of available actions per AWS service :param service_prefix: An AWS service prefix, like `s3` or `kms` :return: A list of actions """ service_prefix_data = get_service_prefix_data(service_prefix) results = [] for item in service_prefix_data["privileges"]: results.append(f"{service_prefix}:{item['privilege']}") return results
def get_condition_value_type(condition_key): """ Get the data type of the condition key - like Date, String, etc. :param condition_key: A condition key, like a4b:filters_deviceType :return: """ service_prefix, condition_name = condition_key.split(":") service_prefix_data = get_service_prefix_data(service_prefix) for condition_key_entry in service_prefix_data["conditions"]: if is_condition_key_match(condition_key_entry["condition"], condition_key): return condition_key_entry["type"].lower()
def get_condition_keys_for_service(service_prefix): """ Get a list of available conditions per AWS service :param service_prefix: An AWS service prefix, like `s3` or `kms` :return: A list of condition keys """ results = [] service_prefix_data = get_service_prefix_data(service_prefix) for resource in service_prefix_data["resources"]: results.extend(resource["condition_keys"]) results = list(dict.fromkeys(results)) return results
def get_resource_type_name_with_raw_arn(raw_arn): """ Given a raw ARN, return the resource type name as shown in the database. :param raw_arn: The raw ARN stored in the database, like 'arn:${Partition}:s3:::${BucketName}' :return: The resource type name, like bucket """ elements = raw_arn.split(":", 5) service_prefix = elements[2] service_data = get_service_prefix_data(service_prefix) for resource in service_data["resources"]: if resource["arn"].lower() == raw_arn.lower(): return resource["resource"]
def get_arn_types_for_service(service_prefix): """ Get a list of available ARN short names per AWS service. Arguments: service_prefix: An AWS service prefix, like `s3` or `kms` Returns: List: A list of ARN types, like `bucket` or `object` """ results = {} service_prefix_data = get_service_prefix_data(service_prefix) for resource_name, resource_data in service_prefix_data["resources"].items(): results[resource_data["resource"]] = resource_data["arn"] return results
def get_raw_arns_for_service(service_prefix): """ Get a list of available raw ARNs per AWS service Arguments: service_prefix: An AWS service prefix, like `s3` or `kms` Returns: List: A list of raw ARNs """ results = [] service_prefix_data = get_service_prefix_data(service_prefix) for resource_name, resource_data in service_prefix_data["resources"].items(): results.append(resource_data["arn"]) return results
def get_actions_for_service(service_prefix): """ Get a list of available actions per AWS service Arguments: service_prefix: List: An AWS service prefix, like `s3` or `kms` Returns: List: A list of actions """ service_prefix_data = get_service_prefix_data(service_prefix) results = [] for item in service_prefix_data["privileges"]: results.append(f"{service_prefix}:{item}") return results
def remove_actions_not_matching_access_level(actions_list, access_level): """ Given a list of actions, return a list of actions that match an access level Arguments: actions_list: A list of actions access_level: 'read', 'write', 'list', 'tagging', or 'permissions-management' Returns: List: An Updated list of actions, where the actions not matching the requested access level are removed. """ new_actions_list = [] def is_access_level(some_service_prefix, some_action): service_prefix_data = get_service_prefix_data( some_service_prefix.lower()) this_result = None if service_prefix_data: if service_prefix_data.get("privileges"): for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data.get("access_level") == access_level: if action_data.get( "privilege").lower() == some_action.lower(): this_result = f"{some_service_prefix}:{action_data.get('privilege')}" break if not this_result: return False else: return this_result if actions_list == ["*"]: actions_list.clear() for some_prefix in all_service_prefixes: service_prefix_data = get_service_prefix_data(some_prefix) for action_name, action_data in service_prefix_data[ "privileges"].items(): if action_data["access_level"] == access_level: actions_list.append( f"{some_prefix}:{action_data['privilege']}") for action in actions_list: try: service_prefix, action_name = action.split(":") except ValueError as v_e: logger.debug(f"{v_e} - for action {action}") continue result = is_access_level(service_prefix, action_name) if result: new_actions_list.append(result) # new_actions_list.append(f"{service_prefix}:{action_name['privilege']}") return new_actions_list
def get_condition_keys_available_to_raw_arn(raw_arn): """ Get a list of condition keys available to a RAW ARN :param raw_arn: The value in the database, like arn:${Partition}:s3:::${BucketName}/${ObjectName} """ results = [] elements = raw_arn.split(":", 5) service_prefix = elements[2] service_prefix_data = get_service_prefix_data(service_prefix) for resource in service_prefix_data["resources"]: if resource["arn"] == raw_arn: results.extend(resource["condition_keys"]) results = list(dict.fromkeys(results)) return results
def get_actions_matching_arn(arn): """Given a user-supplied arn, get a list of all actions that can match it.""" raw_arn = get_matching_raw_arn(arn) resource_type_name = get_resource_type_name_with_raw_arn(raw_arn) service_prefix = get_service_from_arn(raw_arn) service_prefix_data = get_service_prefix_data(service_prefix) results = [] for some_action in service_prefix_data["privileges"]: for some_resource_type in some_action["resource_types"]: this_resource_type = some_resource_type["resource_type"].strip("*") if this_resource_type.lower() == resource_type_name.lower(): results.append(f"{service_prefix}:{some_action['privilege']}") results = list(dict.fromkeys(results)) results.sort() return results
def test_get_service_prefix_data(self): result = get_service_prefix_data("cloud9") desired_output_schema = Schema( { "service_name": "AWS Cloud9", "service_authorization_url": "https://docs.aws.amazon.com/service-authorization/latest/reference/list_awscloud9.html", "prefix": "cloud9", "privileges": dict, "resources": dict, "conditions": dict } ) valid_output = check(desired_output_schema, result) # print(json.dumps(result, indent=4)) self.assertTrue(valid_output)
def get_condition_keys_for_service(service_prefix): """ Get a list of available conditions per AWS service Arguments: service_prefix: An AWS service prefix, like `s3` or `kms` Returns: List: A list of condition keys """ results = [] service_prefix_data = get_service_prefix_data(service_prefix) for condition_key_entry in service_prefix_data["conditions"]: results.append(condition_key_entry["condition"]) results = list(dict.fromkeys(results)) return results