Esempio n. 1
0
def scan_account_authorization_details(
        account_authorization_details_cfg,
        exclusions,
        account_name="default",
        output_directory=os.getcwd(),
        write_data_files=False):  # pragma: no cover
    """
    Given the path to account authorization details files and the exclusions config file, scan all inline and
    managed policies in the account to identify actions that do not leverage resource constraints.
    """

    logger.debug("Identifying modify-only actions that are not leveraging "
                 "resource constraints...")
    check_authorization_details_schema(account_authorization_details_cfg)
    authorization_details = AuthorizationDetails(
        account_authorization_details_cfg)
    results = authorization_details.missing_resource_constraints(
        exclusions, modify_only=True)

    principal_policy_mapping = authorization_details.principal_policy_mapping
    # For the IAM Principals tab, add on risk stats per principal
    for principal_policy_entry in principal_policy_mapping:
        for finding in results:
            if principal_policy_entry.get("PolicyName").lower() == finding.get(
                    "PolicyName").lower():
                principal_policy_entry["Actions"] = len(finding["Actions"])
                principal_policy_entry["PrivilegeEscalation"] = len(
                    finding["PrivilegeEscalation"])
                principal_policy_entry["DataExfiltrationActions"] = len(
                    finding["DataExfiltrationActions"])
                principal_policy_entry["PermissionsManagementActions"] = len(
                    finding["PermissionsManagementActions"])
                principal_name = principal_policy_entry["Principal"]
                # Customer Managed Policies
                if finding.get("Type") == "Policy" and finding.get(
                        "ManagedBy"
                ) == "Customer" and principal_policy_entry.get(
                        "Type") != "Policy":
                    if "Principals" not in finding:
                        finding["Principals"] = [principal_name]
                    else:
                        if principal_name not in finding["Principals"]:
                            finding["Principals"].append(principal_name)

                # AWS Managed Policies
                if finding.get("Type") == "Policy" and finding.get(
                        "ManagedBy") == "AWS":
                    if "Principals" not in finding:
                        finding["Principals"] = [principal_name]
                    else:
                        if principal_name not in finding["Principals"]:
                            finding["Principals"].append(principal_name)

    # Lazy method to get an account ID
    account_id = None
    for item in results:
        if item["ManagedBy"] == "Customer":
            account_id = item["AccountID"]
            break

    html_report = HTMLReport(account_id=account_id,
                             account_name=account_name,
                             results=results,
                             exclusions_cfg=exclusions,
                             principal_policy_mapping=principal_policy_mapping)
    rendered_report = html_report.get_html_report()

    # Raw data file
    if write_data_files:
        if output_directory is None:
            output_directory = os.getcwd()

        # new_data = authorization_details.new_principal_policy_mapping
        # new_raw_data_file = os.path.join(output_directory, f"iam-new-principal-policy-mapping-{account_name}.json")
        # new_raw_data_filepath = write_results_data_file(new_data, new_raw_data_file)
        # print(f"Raw data file saved: {str(new_raw_data_filepath)}")

        raw_data_file = os.path.join(output_directory,
                                     f"iam-results-{account_name}.json")
        raw_data_filepath = write_results_data_file(results, raw_data_file)
        print(f"Raw data file saved: {str(raw_data_filepath)}")

        # Principal policy mapping
        principal_policy_mapping_file = os.path.join(
            output_directory, f"iam-principals-{account_name}.json")
        principal_policy_mapping_filepath = write_results_data_file(
            principal_policy_mapping, principal_policy_mapping_file)
        print(
            f"Principals data file saved: {str(principal_policy_mapping_filepath)}"
        )

        # Create the CSV triage sheet
        create_triage_worksheet(account_name, results, output_directory)

    return rendered_report
Esempio n. 2
0
def generate_html_report(
    account_metadata,
    results,
    principal_policy_mapping,
    output_directory,
    exclusions_cfg,
    skip_open_report=False,
):
    """Create IAM HTML report"""

    account_id = account_metadata.get("account_id")
    account_name = account_metadata.get("account_name")
    html_output_file = os.path.join(output_directory,
                                    f"iam-report-{account_name}.html")
    # sorted_results = sorted(results, key=lambda i: i["PolicyName"])

    # Calculate ratio of policies with PrivEsc, Permissions management, or Data leak potential
    policies_with_data_leak_potential = 0
    policies_with_permissions_management = 0
    policies_with_privilege_escalation = 0

    for finding in results:
        # These are stats we care about regardless of who manages it, as they help with prioritization
        if finding["DataExfiltrationActions"]:
            policies_with_data_leak_potential += 1
        if finding["PrivilegeEscalation"]:
            policies_with_privilege_escalation += 1
        if finding["PermissionsManagementActions"]:
            policies_with_permissions_management += 1

    # MARKDOWN WRITE-UPS
    # Leverage this documentation for setting HTML in the markdown file.
    # We are using markdown because it's just an easier way to modify the general reusable text content.
    # https://python-markdown.github.io/extensions/md_in_html/
    # 1. Overview
    overview_file = codecs.open(
        os.path.join(os.path.dirname(__file__), "templates", "guidance",
                     "1-overview.md"),
        mode="r",
        encoding="utf-8",
    )
    overview_html = markdown.markdown(overview_file.read(),
                                      extensions=["markdown.extensions.extra"])

    # 2. Triage guidance
    triage_guidance_file = codecs.open(
        os.path.join(os.path.dirname(__file__), "templates", "guidance",
                     "2-triage-guidance.md"),
        mode="r",
        encoding="utf-8",
    )
    triage_guidance_html = markdown.markdown(
        triage_guidance_file.read(), extensions=["markdown.extensions.extra"])

    # 3. Remediation Guidance
    remediation_guidance_file = codecs.open(
        os.path.join(
            os.path.dirname(__file__),
            "templates",
            "guidance",
            "3-remediation-guidance.md",
        ),
        mode="r",
        encoding="utf-8",
    )
    remediation_guidance_html = markdown.markdown(
        remediation_guidance_file.read(),
        extensions=["markdown.extensions.extra"])

    # 4. Validation
    validation_guidance_file = codecs.open(
        os.path.join(os.path.dirname(__file__), "templates", "guidance",
                     "4-validation.md"),
        mode="r",
        encoding="utf-8",
    )
    validation_guidance_html = markdown.markdown(
        validation_guidance_file.read(),
        extensions=["markdown.extensions.extra"])

    # 5. Glossary
    glossary_file = codecs.open(
        os.path.join(os.path.dirname(__file__), "templates", "guidance",
                     "glossary.md"),
        mode="r",
        encoding="utf-8",
    )
    glossary_html = markdown.markdown(glossary_file.read(),
                                      extensions=["markdown.extensions.extra"])

    # Formatted results to feed into the HTML
    iam_report_results_formatted = {
        # Metadata
        "account_name": account_name,
        "account_id": account_id,
        "report_generated_time": datetime.datetime.now().strftime("%Y-%m-%d"),
        "cloudsplaining_version": __version__,
        # Actual results
        "results": results,
        # IAM Principals
        "principal_policy_mapping": principal_policy_mapping,
        # Write-ups rendered from markdown
        "overview_write_up": overview_html,
        "triage_guidance_write_up": triage_guidance_html,
        "remediation_guidance_write_up": remediation_guidance_html,
        "validation_guidance_write_up": validation_guidance_html,
        "glossary_write_up": glossary_html,
        # Count of policies with these findings for the stats
        "policies_with_data_leak_potential": policies_with_data_leak_potential,
        "policies_with_privilege_escalation":
        policies_with_privilege_escalation,
        "policies_with_permissions_management":
        policies_with_permissions_management,
        # Exclusions config for appendix and user reference
        "exclusions_configuration": yaml.dump(exclusions_cfg),
    }

    # HTML Report template
    template_path = os.path.join(os.path.dirname(__file__), "templates")
    env = Environment(loader=FileSystemLoader(template_path))  # nosec
    template = env.get_template("template.html")
    with open(html_output_file, "w") as f:
        f.write(template.render(t=iam_report_results_formatted))

    print(f"Wrote HTML results to: {html_output_file}")

    # Open the report by default
    if not skip_open_report:
        print("Opening the HTML report")
        url = "file://%s" % os.path.abspath(html_output_file)
        webbrowser.open(url, new=2)

    # Create the CSV triage sheet
    create_triage_worksheet(account_name, results, output_directory)