def get_actions_with_access_level(db_session, service, access_level): """ Get a list of actions in a service under different access levels. :param db_session: SQLAlchemy database session object :param service: 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 """ actions_list = [] all_services = get_all_service_prefixes(db_session) if service == "all": for serv in all_services: output = get_actions_with_access_level(db_session, serv, access_level) actions_list.extend(output) rows = db_session.query(ActionTable).filter( and_( ActionTable.service.like(service), ActionTable.access_level.ilike(access_level), ) ) # Create a list of actions under each service. Use this list to pass in to the remove_actions_not_matching_access_level function # which will give you the list of actions you want. for row in rows: action = get_full_action_name(row.service, row.name) if action not in actions_list: actions_list.append(action) return actions_list
def validate_services_from_file(services: list): valid_aws_services = get_all_service_prefixes() for service in services: if service not in valid_aws_services: raise Exception( f"{service} is not a valid AWS service. Please supply a valid AWS service name and try again." )
def service_wildcard(self) -> List[str]: """Determine if the policy gives access to all actions within a service - simple grepping""" services = set() all_service_prefixes = get_all_service_prefixes() for statement in self.statements: logger.debug("Evaluating statement: %s", statement.json) if statement.effect_allow: if isinstance(statement.actions, list): for action in statement.actions: # If the action is a straight up * if action == "*": logger.debug( "All actions are allowed by this policy") services.update(all_service_prefixes) # Otherwise, it will take the format of service:* else: service, this_action = action.split(":") # service:* if this_action == "*": services.add(service) elif isinstance(statement.actions, str): # If the action is a straight up * if statement.actions == "*": logger.debug("All actions are allowed by this policy") services.update(all_service_prefixes) else: service, this_action = statement.actions.split(":") # service:* if this_action == "*": services.add(service) return sorted(services)
def initialize(access_level_overrides_file, fetch, build): """ Initialize the local database to store AWS IAM information, which can be used to generate IAM policies, and for querying the database. """ if not access_level_overrides_file: overrides_file = HOME + CONFIG_DIRECTORY + 'access-level-overrides.yml' else: overrides_file = access_level_overrides_file # Create the config directory database_path = create_policy_sentry_config_directory() # Copy over the html docs, which will be used to build the database create_html_docs_directory() # Create the directory to download IAM policies to create_policy_analysis_directory() # Create audit directory to host list of permissions for analyze_iam_policy create_audit_directory() # Create overrides file, which allows us to override the Access Levels # provided by AWS documentation create_default_overrides_file() # Create the default reporting configuration file. This is used by # analyze_iam_policy create_default_report_config_file() if not build and not fetch: # copy from the bundled database location to the destination path shutil.copy(BUNDLED_DATABASE_FILE_PATH, database_path) # Connect to the database at that path with SQLAlchemy db_session = connect_db(database_path, initialization=True) # --fetch: wget the AWS IAM Actions, Resources and Condition Keys pages and store them locally. # if --build and --fetch are both supplied, just do --fetch if fetch: # `wget` the html docs to the local directory update_html_docs_directory(HTML_DIRECTORY_PATH) # Update the links.yml file prefix_list = create_service_links_mapping_file( HTML_DIRECTORY_PATH, LINKS_YML_FILE_LOCAL) print(f"Services: {prefix_list}") # initialize --build if build or access_level_overrides_file or fetch: # Use the list of services that were listed in the links.yml file all_aws_services = get_list_of_service_prefixes_from_links_file( LINKS_YML_FILE_LOCAL) print(f"Services to build for: ${LINKS_YML_FILE_LOCAL}") # Fill in the database with data on the AWS services create_database(db_session, all_aws_services, overrides_file) print("Created tables for all services!") # Query the database for all the services that are now in the database. all_aws_service_prefixes = get_all_service_prefixes(db_session) total_count_of_services = str(len(all_aws_service_prefixes)) print(f"{total_count_of_services} AWS services in the database. \nServices: {all_aws_service_prefixes}")
def initialize(access_level_overrides_file, fetch, build, log_level): """ Initialize the local database to store AWS IAM information, which can be used to generate IAM policies, and for querying the database. """ set_log_level(logger, log_level) if not access_level_overrides_file: overrides_file = HOME + CONFIG_DIRECTORY + "access-level-overrides.yml" else: overrides_file = access_level_overrides_file # Create the config directory database_path = create_policy_sentry_config_directory() # Copy over the html docs, which will be used to build the database create_html_docs_directory() # Create overrides file, which allows us to override the Access Levels # provided by AWS documentation create_default_overrides_file() print("Database will be stored here: %s", database_path) if not build and not fetch: # copy from the bundled database location to the destination path shutil.copy(BUNDLED_DATABASE_FILE_PATH, database_path) # Connect to the database at that path with SQLAlchemy db_session = connect_db(database_path, initialization=True) # --fetch: wget the AWS IAM Actions, Resources and Condition Keys pages and store them locally. # if --build and --fetch are both supplied, just do --fetch if fetch: # `wget` the html docs to the local directory update_html_docs_directory(HTML_DIRECTORY_PATH) # Update the links.yml file prefix_list = create_service_links_mapping_file( HTML_DIRECTORY_PATH, LINKS_YML_FILE_LOCAL) print(f"Services: {prefix_list}") # initialize --build if build or access_level_overrides_file or fetch: # Use the list of services that were listed in the links.yml file all_aws_services = get_list_of_service_prefixes_from_links_file( LINKS_YML_FILE_LOCAL) logger.debug("Services to build are stored in: %s", LINKS_YML_FILE_LOCAL) # Fill in the database with data on the AWS services create_database(db_session, all_aws_services, overrides_file) print("Created tables for all services!") # Query the database for all the services that are now in the database. all_aws_service_prefixes = get_all_service_prefixes(db_session) total_count_of_services = str(len(all_aws_service_prefixes)) print("Initialization complete!") print(f"Total AWS services in the IAM database: {total_count_of_services}") logger.debug("\nService prefixes:") logger.debug(", ".join(all_aws_service_prefixes))
def action_table(name, service, access_level, condition, wildcard_only): """Query the Action Table from the Policy Sentry database""" db_session = connect_db(DATABASE_FILE_PATH) # Actions on all services if service == "all": all_services = get_all_service_prefixes(db_session) if access_level: level = transform_access_level_text(access_level) print(f"{access_level} actions across ALL services:\n") results = [] for serv in all_services: output = get_actions_with_access_level(db_session, serv, level) results.extend(output) for result in results: print(result) # Get a list of all services in the database else: print("All services in the database:\n") for item in all_services: print(item) elif name is None and access_level: print( f"All IAM actions under the {service} service that have the access level {access_level}:" ) level = transform_access_level_text(access_level) output = get_actions_with_access_level(db_session, service, level) print(json.dumps(output, indent=4)) # Get a list of all IAM actions under the service that support the # specified condition key. elif condition: print( f"IAM actions under {service} service that support the {condition} condition only:" ) output = get_actions_matching_condition_key(db_session, service, condition) print(json.dumps(output, indent=4)) # Get a list of IAM Actions under the service that only support resources = "*" # (i.e., you cannot restrict it according to ARN) elif wildcard_only: print( f"IAM actions under {service} service that support wildcard resource values only:" ) output = get_actions_that_support_wildcard_arns_only( db_session, service) print(json.dumps(output, indent=4)) elif name and access_level is None: output = get_action_data(db_session, service, name) print(json.dumps(output, indent=4)) else: print(f"All IAM actions available to {service}:") # Get a list of all IAM Actions available to the service action_list = get_actions_for_service(db_session, service) print(f"ALL {service} actions:") for item in action_list: print(item)
def initialize(access_level_overrides_file, fetch, build): """ Initialize the local data file to store AWS IAM information, which can be used to generate IAM policies, and for querying the database. """ if not access_level_overrides_file: overrides_file = LOCAL_ACCESS_OVERRIDES_FILE else: overrides_file = access_level_overrides_file # Create the config directory database_path = create_policy_sentry_config_directory() # Copy over the html docs, which will be used to build the database create_html_docs_directory() # Create overrides file, which allows us to override the Access Levels # provided by AWS documentation file_list = [ f for f in os.listdir(BUNDLED_DATA_DIRECTORY) if os.path.isfile(os.path.join(BUNDLED_DATA_DIRECTORY, f)) ] for file in file_list: if file.endswith(".yml"): shutil.copy(os.path.join(BUNDLED_DATA_DIRECTORY, file), CONFIG_DIRECTORY) logger.debug("copying overrides file %s to %s", file, CONFIG_DIRECTORY) print("Database will be stored here: " + database_path) if not build and not fetch: # copy from the bundled database location to the destination path shutil.copy(BUNDLED_DATASTORE_FILE_PATH, database_path) # --fetch: wget the AWS IAM Actions, Resources and Condition Keys pages and store them locally. # if --build and --fetch are both supplied, just do --fetch if fetch: # `wget` the html docs to the local directory update_html_docs_directory(LOCAL_HTML_DIRECTORY_PATH) create_database(CONFIG_DIRECTORY, overrides_file) # initialize --build if build or access_level_overrides_file or fetch: create_database(CONFIG_DIRECTORY, overrides_file) print("Created the database!") # Query the database for all the services that are now in the database. all_aws_service_prefixes = get_all_service_prefixes() total_count_of_services = str(len(all_aws_service_prefixes)) print("Initialization complete!") print(f"Total AWS services in the IAM database: {total_count_of_services}") logger.debug("\nService prefixes:") logger.debug(", ".join(all_aws_service_prefixes))
def initialize(access_level_overrides_file, fetch): """ Create a local database to store AWS IAM information, which can be used to generate IAM policies and analyze them for least privilege. """ # Create the config directory database_path = create_policy_sentry_config_directory() # Copy over the html docs, which will be used to build the database create_html_docs_directory() # Create the directory to download IAM policies to create_policy_analysis_directory() # Create audit directory to host list of permissions for analyze_iam_policy create_audit_directory() # Create overrides file, which allows us to override the Access Levels # provided by AWS documentation create_default_overrides_file() # Create the default reporting configuration file. This is used by # analyze_iam_policy create_default_report_config_file() # If the user specifies fetch, wget the AWS IAM Actions, Resources and Condition Keys pages and store them locally. if fetch: # `wget` the html docs to the local directory update_html_docs_directory(HTML_DIRECTORY_PATH) # Update the links.yml file prefix_list = create_service_links_mapping_file( HTML_DIRECTORY_PATH, LINKS_YML_FILE_LOCAL) print(f"Services: {prefix_list}") # Connect to the database at that path with SQLAlchemy db_session = connect_db(database_path, initialization=True) # Use the list of services that were listed in the links.yml file all_aws_services = get_list_of_service_prefixes_from_links_file( LINKS_YML_FILE_LOCAL) print(f"Services to build for: ${LINKS_YML_FILE_LOCAL}") # Fill in the database with data on the AWS services create_database(db_session, all_aws_services, access_level_overrides_file) print("Created tables for all services!") # Query the database for all the services that are now in the database. all_aws_service_prefixes = get_all_service_prefixes(db_session) total_count_of_services = str(len(all_aws_service_prefixes)) print( f"{total_count_of_services} AWS services in the database. \nServices: {all_aws_service_prefixes}" )
def service_wildcard(self): """Determine if the policy gives access to all actions within a service - simple grepping""" services = [] for statement in self.statements: logger.debug("Evaluating statement: %s", statement.json) if statement.effect == "Allow": if isinstance(statement.actions, list): for action in statement.actions: # If the action is a straight up * if action == "*": logger.debug( "All actions are allowed by this policy") services.extend(get_all_service_prefixes()) # Otherwise, it will take the format of service:* else: service, this_action = action.split(":") # service:* if this_action == "*": services.append(service) elif isinstance(statement.actions, str): # If the action is a straight up * if statement.actions == "*": logger.debug("All actions are allowed by this policy") services.append(get_all_service_prefixes()) else: service, this_action = statement.actions.split(":") # service:* if this_action == "*": services.append(service) if services: # Remove duplicates and sort services = list(dict.fromkeys(services)) these_services = services.copy() these_services.sort() return these_services else: return []
""" Methods that execute specific queries against the database for the ACTIONS table. This supports the Policy Sentry query functionality """ import logging import functools from policy_sentry.shared.iam_data import iam_definition, get_service_prefix_data from policy_sentry.querying.all import get_all_service_prefixes from policy_sentry.querying.arns import get_matching_raw_arns, get_resource_type_name_with_raw_arn from policy_sentry.util.arns import get_service_from_arn all_service_prefixes = get_all_service_prefixes() logger = logging.getLogger(__name__) @functools.lru_cache(maxsize=1024) 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 = [] if isinstance(service_prefix_data, dict): for item in service_prefix_data["privileges"]: results.append(f"{service_prefix}:{item}") return results
def query_action_table(name, service, access_level, condition, resource_type, fmt="json"): """Query the Action Table from the Policy Sentry database. Use this one when leveraging Policy Sentry as a library.""" if os.path.exists(LOCAL_DATASTORE_FILE_PATH): logger.info( f"Using the Local IAM definition: {LOCAL_DATASTORE_FILE_PATH}. To leverage the bundled definition instead, remove the folder $HOME/.policy_sentry/" ) else: # Otherwise, leverage the datastore inside the python package logger.debug("Leveraging the bundled IAM Definition.") # Actions on all services if service == "all": all_services = get_all_service_prefixes() if access_level: level = transform_access_level_text(access_level) print(f"{access_level} actions across ALL services:\n") output = [] for serv in all_services: result = get_actions_with_access_level(serv, level) output.extend(result) print(yaml.dump(output)) if fmt == "yaml" else [ print(result) for result in output ] # Get a list of all services in the database else: print("All services in the database:\n") output = all_services print(yaml.dump(output)) if fmt == "yaml" else [ print(item) for item in output ] elif name is None and access_level and not resource_type: print( f"All IAM actions under the {service} service that have the access level {access_level}:" ) level = transform_access_level_text(access_level) output = get_actions_with_access_level(service, level) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] elif name is None and access_level and resource_type: print( f"{service} {access_level.upper()} actions that have the resource type {resource_type.upper()}:" ) access_level = transform_access_level_text(access_level) output = get_actions_with_arn_type_and_access_level( service, resource_type, access_level) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] # Get a list of all IAM actions under the service that support the specified condition key. elif condition: print( f"IAM actions under {service} service that support the {condition} condition only:" ) output = get_actions_matching_condition_key(service, condition) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] # Get a list of IAM Actions under the service that only support resources = "*" # (i.e., you cannot restrict it according to ARN) elif resource_type: print( f"IAM actions under {service} service that have the resource type {resource_type}:" ) output = get_actions_matching_arn_type(service, resource_type) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] elif name and access_level is None: output = get_action_data(service, name) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] else: # Get a list of all IAM Actions available to the service output = get_actions_for_service(service) print(f"ALL {service} actions:") print(yaml.dump(output)) if fmt == "yaml" else [ print(item) for item in output ] return output
import os import requests from bs4 import BeautifulSoup from policy_sentry.querying.all import get_all_service_prefixes from aws_allowlister.database.raw_scraping_data import RawScrapingData from aws_allowlister.scrapers.aws_docs import get_aws_html from aws_allowlister.shared.utils import clean_service_name from sqlalchemy.orm.session import Session ALL_SERVICE_PREFIXES = get_all_service_prefixes() def scrape_hipaa_table(db_session: Session, link: str, destination_folder: str, file_name: str, download: bool = True): html_file_path = os.path.join(destination_folder, file_name) if os.path.exists(html_file_path): os.remove(html_file_path) if download: if os.path.exists(html_file_path): os.remove(html_file_path) get_aws_html(link, html_file_path) raw_scraping_data = RawScrapingData() # These show up as list items but are not relevant at all false_positives = [ "AWS Cloud Security",
def generate(all_standards, soc, pci, hipaa, iso, fedramp_high, fedramp_moderate, dodccsrg_il2_ew, dodccsrg_il2_gc, dodccsrg_il4_gc, dodccsrg_il5_gc, hitrust_csf, irap, include, include_file, exclude, exclude_file, table, json_list, excluded_table, excluded_json_list, quiet): standards = [] if quiet: log_level = getattr(logging, "WARNING") set_stream_logger(level=log_level) else: log_level = getattr(logging, "INFO") set_stream_logger(level=log_level) # If include-file argument is supplied, then read the file and use it as the include args. if include_file: include = utils.read_yaml_file(include_file) validate_services_from_file(services=include) # Same thing with exclude-file argument if exclude_file: exclude = utils.read_yaml_file(exclude_file) validate_services_from_file(services=exclude) # Compile list of standards if soc: standards.append("SOC") if pci: standards.append("PCI") if hipaa: standards.append("HIPAA") if iso: standards.append("ISO") if fedramp_high: standards.append("FedRAMP_High") if fedramp_moderate: standards.append("FedRAMP_Moderate") if dodccsrg_il2_ew: standards.append("DoDCCSRG_IL2_EW") if dodccsrg_il2_gc: standards.append("DoDCCSRG_IL2_GC") if dodccsrg_il4_gc: standards.append("DoDCCSRG_IL4_GC") if dodccsrg_il5_gc: standards.append("DoDCCSRG_IL5_GC") if hitrust_csf: standards.append("HITRUST") if irap: standards.append("IRAP") if (all_standards and not soc and not pci and not hipaa and not iso and not fedramp_high and not fedramp_moderate and not dodccsrg_il2_ew and not dodccsrg_il2_gc and not dodccsrg_il4_gc and not dodccsrg_il5_gc and not hitrust_csf and not irap): standards = [ "SOC", "PCI", "HIPAA", "ISO", "FedRAMP_High", "FedRAMP_Moderate" ] logger.info( f"--all was selected. The policy will include the default standard(s): {str(', '.join(standards))}" ) if (not all_standards and not soc and not pci and not hipaa and not iso and not fedramp_high and not fedramp_moderate and not dodccsrg_il2_ew and not dodccsrg_il2_gc and not dodccsrg_il4_gc and not dodccsrg_il5_gc and not hitrust_csf and not irap): standards = [ "SOC", "PCI", "HIPAA", "ISO", "FedRAMP_High", "FedRAMP_Moderate" ] logger.info( f"--all was selected. The policy will include the default standard(s): {str(', '.join(standards))}" ) logger.info(f"Note: to silence these logs, supply the argument '--quiet'") logger.info(f"Policies for standard(s): {str(', '.join(standards))}") # If --table is provided, print as Markdown table. Otherwise, print the JSON policy if table: services = generate_allowlist_service_prefixes(standards, include, exclude) services_tabulated = [] headers = ["Service Prefix", "Service Name"] # services_tabulated.append(headers) for service_prefix in services: service_name = utils.get_service_name_matching_iam_service_prefix( service_prefix) try: service_authorization_url = get_service_authorization_url( service_prefix) except AttributeError as error: logger.info(error) service_authorization_url = "" service_name_text = f"[{service_name}]({service_authorization_url})" # services_tabulated.append([service_prefix, service_name]) services_tabulated.append([service_prefix, service_name_text]) print(tabulate(services_tabulated, headers=headers, tablefmt="github")) elif json_list: services_json = {} services = generate_allowlist_service_prefixes(standards, include, exclude) for service_prefix in services: service_name = utils.get_service_name_matching_iam_service_prefix( service_prefix) try: service_authorization_url = get_service_authorization_url( service_prefix) except AttributeError as error: logger.info(error) service_authorization_url = "" services_json.update({ service_prefix: { 'service_name': service_name, 'service_authorization_url': service_authorization_url } }) print(json.dumps(services_json, indent=2)) elif excluded_table: # Get the list of allowlist prefixes allowed_services = generate_allowlist_service_prefixes( standards, include, exclude) # Get the list of all service prefixes, not just the allowlist ones all_services = get_all_service_prefixes() # Create a list of services that don't exist in allowed_services excluded_services = [] for service_prefix in all_services: if service_prefix not in allowed_services: excluded_services.append(service_prefix) excluded_services.sort() # Create the table services_tabulated = [] headers = ["Service Prefix", "Service Name"] for service_prefix in excluded_services: service_name = utils.get_service_name_matching_iam_service_prefix( service_prefix) service_authorization_url = get_service_authorization_url( service_prefix) service_name_text = f"[{service_name}]({service_authorization_url})" # services_tabulated.append([service_prefix, service_name]) services_tabulated.append([service_prefix, service_name_text]) print(tabulate(services_tabulated, headers=headers, tablefmt="github")) elif excluded_json_list: services_json = {} allowed_services = generate_allowlist_service_prefixes( standards, include, exclude) all_services = get_all_service_prefixes() excluded_services = [] for service_prefix in all_services: if service_prefix not in allowed_services: excluded_services.append(service_prefix) excluded_services.sort() for service_prefix in excluded_services: service_name = utils.get_service_name_matching_iam_service_prefix( service_prefix) try: service_authorization_url = get_service_authorization_url( service_prefix) except AttributeError as error: logger.info(error) service_authorization_url = "" services_json.update({ service_prefix: { 'service_name': service_name, 'service_authorization_url': service_authorization_url } }) print(json.dumps(services_json, indent=2)) else: results = generate_allowlist_scp(standards, include, exclude) minified_results = f"""{{ "Version": "2012-10-17", "Statement": {{ "Sid": "AllowList", "Effect": "Deny", "Resource": "*", "NotAction": {json.dumps(results.get('Statement').get('NotAction'))} }} }}""" print(minified_results)
def test_get_all_service_prefixes(self): result = get_all_service_prefixes() self.assertGreater(len(result), 212)
def query_action_table(name, service, access_level, condition, wildcard_only, fmt="json"): """Query the Action Table from the Policy Sentry database. Use this one when leveraging Policy Sentry as a library.""" # Actions on all services if service == "all": all_services = get_all_service_prefixes() if access_level: level = transform_access_level_text(access_level) print(f"{access_level} actions across ALL services:\n") output = [] for serv in all_services: result = get_actions_with_access_level(serv, level) output.extend(result) print(yaml.dump(output)) if fmt == "yaml" else [ print(result) for result in output ] # Get a list of all services in the database else: print("All services in the database:\n") output = all_services print(yaml.dump(output)) if fmt == "yaml" else [ print(item) for item in output ] elif name is None and access_level and not wildcard_only: print( f"All IAM actions under the {service} service that have the access level {access_level}:" ) level = transform_access_level_text(access_level) output = get_actions_with_access_level(service, level) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] elif name is None and access_level and wildcard_only: print( f"{service} {access_level.upper()} actions that must use wildcards in the resources block:" ) access_level = transform_access_level_text(access_level) output = get_actions_at_access_level_that_support_wildcard_arns_only( service, access_level) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] # Get a list of all IAM actions under the service that support the specified condition key. elif condition: print( f"IAM actions under {service} service that support the {condition} condition only:" ) output = get_actions_matching_condition_key(service, condition) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] # Get a list of IAM Actions under the service that only support resources = "*" # (i.e., you cannot restrict it according to ARN) elif wildcard_only: print( f"IAM actions under {service} service that support wildcard resource values only:" ) output = get_actions_that_support_wildcard_arns_only(service) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] elif name and access_level is None: output = get_action_data(service, name) print(yaml.dump(output)) if fmt == "yaml" else [ print(json.dumps(output, indent=4)) ] else: # Get a list of all IAM Actions available to the service output = get_actions_for_service(service) print(f"ALL {service} actions:") print(yaml.dump(output)) if fmt == "yaml" else [ print(item) for item in output ] return output
#!/usr/bin/env python from policy_sentry.shared.database import connect_db from policy_sentry.querying.all import get_all_service_prefixes if __name__ == '__main__': db_session = connect_db('bundled') all_service_prefixes = get_all_service_prefixes(db_session) print(all_service_prefixes) """ Output: A list of every service prefix (like 'kms' or 's3') available in the IAM database. Note that this will not include services that do not support any ARN types, like AWS IQ. """