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))
Beispiel #2
0
def write_policy_dir(input_dir, output_dir, minimize, log_level):
    """
    write_policy, but this time with an input directory of YML/YAML files, and an output directory for all the JSON files
    """
    set_log_level(logger, log_level)

    db_session = connect_db(DATABASE_FILE_PATH)
    input_dir = os.path.abspath(input_dir)
    output_dir = os.path.abspath(output_dir)

    if not minimize:
        logger.warning(
            "Note: --minimize option is not set. If the policy is too large, "
            "it can hit the AWS IAM Policy character limit. "
            "We'll execute as-is, but try using `--minimize 0` functionality "
            "for production to optimize policy size.\n")
    # Construct the path
    # Get the list of files
    # Write a list of the names
    if not check_valid_file_path(input_dir):
        logger.critical("Input directory is invalid")
        sys.exit()
    if not check_valid_file_path(output_dir):
        logger.critical("Output directory is invalid")
        sys.exit()

    input_files = glob.glob(str(input_dir + "/*.yml"), recursive=False)
    if not input_files:
        logger.critical(
            "Directory is empty or does not have files with *.yml extension. "
            "Please check the folder contents and/or extension spelling.")

    logger.info("Writing the policy JSON files from %s to %s...\n", input_dir,
                output_dir)
    for yaml_file in input_files:
        # Get the name of the file, and strip the extension. This is what the
        # policy name will be
        base_name = os.path.basename(yaml_file)
        base_name_no_extension = os.path.splitext(
            os.path.basename(yaml_file))[0]
        cfg = read_yaml_file(yaml_file)
        policy = write_policy_with_template(db_session, cfg, minimize)
        logger.info("Writing policy for %s\n", base_name)

        target_file = str(output_dir + "/" + base_name_no_extension + ".json")
        if os.path.exists(target_file):
            logger.info(
                "Target file for %s.json exists in the target directory. "
                "Removing it and writing a new file.\n",
                target_file,
            )
            os.remove(target_file)
        write_json_file(target_file, policy)

    logger.info("Finished")
Beispiel #3
0
def condition_table(name, service, fmt, log_level):
    """Query the condition keys table from the Policy Sentry database"""
    set_log_level(logger, log_level)

    db_session = connect_db(DATABASE_FILE_PATH)
    # Get a list of all condition keys available to the service
    if name is None:
        results = get_condition_keys_for_service(db_session, service)
        print(yaml.dump(results)) if fmt == "yaml" else [
            print(item) for item in results
        ]
    # Get details on the specific condition key
    else:
        output = get_condition_key_details(db_session, service, name)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
def write_policy(input_file, minimize, log_level):
    """
    Write a least-privilege IAM Policy by supplying either a list of actions or
    access levels specific to resource ARNs!
    """
    set_log_level(logger, log_level)

    db_session = connect_db(DATABASE_FILE_PATH)

    if input_file:
        cfg = read_yaml_file(input_file)
    else:
        try:
            cfg = yaml.safe_load(sys.stdin)
        except yaml.YAMLError as exc:
            logger.critical(exc)
            sys.exit()
    policy = write_policy_with_template(db_session, cfg, minimize)
    print(json.dumps(policy, indent=4))
Beispiel #5
0
def create_template(output_file, template_type, name, log_level):
    """
    Writes YML file templates for use in the write-policy
    command, so users can fill out the fields
    without needing to look up the required format.
    """
    set_log_level(logger, log_level)

    filename = Path(output_file).resolve()
    if template_type == "actions":
        actions_template = create_actions_template(name)
        with open(filename, "a") as file_obj:
            for line in actions_template:
                file_obj.write(line)

    if template_type == "crud":
        crud_template = create_crud_template(name)
        with open(filename, "a") as file_obj:
            for line in crud_template:
                file_obj.write(line)

    print(f"write-policy template file written to: {filename}")
Beispiel #6
0
def arn_table(name, service, list_arn_types, fmt, log_level):
    """Query the ARN Table from the Policy Sentry database"""
    set_log_level(logger, log_level)

    db_session = connect_db(DATABASE_FILE_PATH)
    # Get a list of all RAW ARN formats available through the service.
    if name is None and list_arn_types is False:
        raw_arns = get_raw_arns_for_service(db_session, service)
        print(yaml.dump(raw_arns)) if fmt == "yaml" else [
            print(item) for item in raw_arns
        ]
    # Get a list of all the ARN types per service, paired with the RAW ARNs
    elif name is None and list_arn_types:
        output = get_arn_types_for_service(db_session, service)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    # Get the raw ARN format for the `cloud9` service with the short name
    # `environment`
    else:
        output = get_arn_type_details(db_session, service, name)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
Beispiel #7
0
def action_table(name, service, access_level, condition, wildcard_only, fmt, log_level):
    """Query the Action Table from the Policy Sentry database"""
    set_log_level(logger, log_level)

    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)
            print(yaml.dump(results)) if fmt == "yaml" else [
                print(result) for result in results
            ]
        # Get a list of all services in the database
        else:
            print("All services in the database:\n")
            print(yaml.dump(all_services)) if fmt == "yaml" else [
                print(item) for item in all_services
            ]
    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(db_session, 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:"
        )
        output = get_actions_at_access_level_that_support_wildcard_arns_only(
            db_session, 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(db_session, 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(db_session, 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(db_session, 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
        action_list = get_actions_for_service(db_session, service)
        print(f"ALL {service} actions:")
        print(yaml.dump(action_list)) if fmt == "yaml" else [
            print(item) for item in action_list
        ]