mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(MITRE): add MITRE ATT&CK framework for AWS (#2537)
This commit is contained in:
2075
prowler/compliance/aws/mitre_attack_aws.json
Normal file
2075
prowler/compliance/aws/mitre_attack_aws.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,7 @@ import sys
|
||||
|
||||
from pydantic import parse_obj_as
|
||||
|
||||
from prowler.lib.check.compliance_models import (
|
||||
Compliance_Base_Model,
|
||||
Compliance_Requirement,
|
||||
)
|
||||
from prowler.lib.check.compliance_models import Compliance_Base_Model
|
||||
from prowler.lib.check.models import Check_Metadata_Model
|
||||
from prowler.lib.logger import logger
|
||||
|
||||
@@ -22,16 +19,7 @@ def update_checks_metadata_with_compliance(
|
||||
compliance_requirements = []
|
||||
# Verify if check is in the requirement
|
||||
if check in requirement.Checks:
|
||||
# Create the Compliance_Requirement
|
||||
requirement = Compliance_Requirement(
|
||||
Id=requirement.Id,
|
||||
Description=requirement.Description,
|
||||
Attributes=requirement.Attributes,
|
||||
Checks=requirement.Checks,
|
||||
)
|
||||
# For the check metadata we don't need the "Checks" key
|
||||
delattr(requirement, "Checks")
|
||||
# Include the requirment into the check's framework requirements
|
||||
# Include the requirement into the check's framework requirements
|
||||
compliance_requirements.append(requirement)
|
||||
# Create the Compliance_Model
|
||||
compliance = Compliance_Base_Model(
|
||||
|
||||
@@ -8,8 +8,8 @@ from prowler.lib.logger import logger
|
||||
|
||||
|
||||
# ENS - Esquema Nacional de Seguridad - España
|
||||
class ENS_Requirements_Nivel(str, Enum):
|
||||
"""ENS V3 Requirements Level"""
|
||||
class ENS_Requirement_Attribute_Nivel(str, Enum):
|
||||
"""ENS V3 Requirement Attribute Level"""
|
||||
|
||||
opcional = "opcional"
|
||||
bajo = "bajo"
|
||||
@@ -17,8 +17,8 @@ class ENS_Requirements_Nivel(str, Enum):
|
||||
alto = "alto"
|
||||
|
||||
|
||||
class ENS_Requirements_Dimensiones(str, Enum):
|
||||
"""ENS V3 Requirements Dimensions"""
|
||||
class ENS_Requirement_Attribute_Dimensiones(str, Enum):
|
||||
"""ENS V3 Requirement Attribute Dimensions"""
|
||||
|
||||
confidencialidad = "confidencialidad"
|
||||
integridad = "integridad"
|
||||
@@ -27,8 +27,8 @@ class ENS_Requirements_Dimensiones(str, Enum):
|
||||
disponibilidad = "disponibilidad"
|
||||
|
||||
|
||||
class ENS_Requirements_Tipos(str, Enum):
|
||||
"""ENS Requirements Tipos"""
|
||||
class ENS_Requirement_Attribute_Tipos(str, Enum):
|
||||
"""ENS Requirement Attribute Tipos"""
|
||||
|
||||
refuerzo = "refuerzo"
|
||||
requisito = "requisito"
|
||||
@@ -36,21 +36,21 @@ class ENS_Requirements_Tipos(str, Enum):
|
||||
medida = "medida"
|
||||
|
||||
|
||||
class ENS_Requirements(BaseModel):
|
||||
"""ENS V3 Framework Requirements"""
|
||||
class ENS_Requirement_Attribute(BaseModel):
|
||||
"""ENS V3 Framework Requirement Attribute"""
|
||||
|
||||
IdGrupoControl: str
|
||||
Marco: str
|
||||
Categoria: str
|
||||
DescripcionControl: str
|
||||
Tipo: ENS_Requirements_Tipos
|
||||
Nivel: ENS_Requirements_Nivel
|
||||
Dimensiones: list[ENS_Requirements_Dimensiones]
|
||||
Tipo: ENS_Requirement_Attribute_Tipos
|
||||
Nivel: ENS_Requirement_Attribute_Nivel
|
||||
Dimensiones: list[ENS_Requirement_Attribute_Dimensiones]
|
||||
|
||||
|
||||
# Generic Compliance Requirements
|
||||
class Generic_Compliance_Requirements(BaseModel):
|
||||
"""Generic Compliance Requirements"""
|
||||
# Generic Compliance Requirement Attribute
|
||||
class Generic_Compliance_Requirement_Attribute(BaseModel):
|
||||
"""Generic Compliance Requirement Attribute"""
|
||||
|
||||
ItemId: str
|
||||
Section: Optional[str]
|
||||
@@ -60,27 +60,27 @@ class Generic_Compliance_Requirements(BaseModel):
|
||||
Soc_Type: Optional[str]
|
||||
|
||||
|
||||
class CIS_Requirements_Profile(str):
|
||||
"""CIS Requirements Profile"""
|
||||
class CIS_Requirement_Attribute_Profile(str):
|
||||
"""CIS Requirement Attribute Profile"""
|
||||
|
||||
Level_1 = "Level 1"
|
||||
Level_2 = "Level 2"
|
||||
|
||||
|
||||
class CIS_Requirements_AssessmentStatus(str):
|
||||
"""CIS Requirements Assessment Status"""
|
||||
class CIS_Requirement_Attribute_AssessmentStatus(str):
|
||||
"""CIS Requirement Attribute Assessment Status"""
|
||||
|
||||
Manual = "Manual"
|
||||
Automated = "Automated"
|
||||
|
||||
|
||||
# CIS Requirements
|
||||
class CIS_Requirements(BaseModel):
|
||||
"""CIS Requirements"""
|
||||
# CIS Requirement Attribute
|
||||
class CIS_Requirement_Attribute(BaseModel):
|
||||
"""CIS Requirement Attribute"""
|
||||
|
||||
Section: str
|
||||
Profile: CIS_Requirements_Profile
|
||||
AssessmentStatus: CIS_Requirements_AssessmentStatus
|
||||
Profile: CIS_Requirement_Attribute_Profile
|
||||
AssessmentStatus: CIS_Requirement_Attribute_AssessmentStatus
|
||||
Description: str
|
||||
RationaleStatement: str
|
||||
ImpactStatement: str
|
||||
@@ -90,9 +90,9 @@ class CIS_Requirements(BaseModel):
|
||||
References: str
|
||||
|
||||
|
||||
# Well Architected Requirements
|
||||
class AWS_Well_Architected_Requirements(BaseModel):
|
||||
"""AWS Well Architected Requirements"""
|
||||
# Well Architected Requirement Attribute
|
||||
class AWS_Well_Architected_Requirement_Attribute(BaseModel):
|
||||
"""AWS Well Architected Requirement Attribute"""
|
||||
|
||||
Name: str
|
||||
WellArchitectedQuestionId: str
|
||||
@@ -105,9 +105,9 @@ class AWS_Well_Architected_Requirements(BaseModel):
|
||||
ImplementationGuidanceUrl: str
|
||||
|
||||
|
||||
# ISO27001 Requirements
|
||||
class ISO27001_2013_Requirements(BaseModel):
|
||||
"""ISO27001 Requirements"""
|
||||
# ISO27001 Requirement Attribute
|
||||
class ISO27001_2013_Requirement_Attribute(BaseModel):
|
||||
"""ISO27001 Requirement Attribute"""
|
||||
|
||||
Category: str
|
||||
Objetive_ID: str
|
||||
@@ -115,6 +115,31 @@ class ISO27001_2013_Requirements(BaseModel):
|
||||
Check_Summary: str
|
||||
|
||||
|
||||
# MITRE Requirement Attribute
|
||||
class Mitre_Requirement_Attribute(BaseModel):
|
||||
"""MITRE Requirement Attribute"""
|
||||
|
||||
AWSService: str
|
||||
Category: str
|
||||
Value: str
|
||||
Comment: str
|
||||
|
||||
|
||||
# MITRE Requirement
|
||||
class Mitre_Requirement(BaseModel):
|
||||
"""Mitre_Requirement holds the model for every MITRE requirement"""
|
||||
|
||||
Name: str
|
||||
Id: str
|
||||
Tactics: list[str]
|
||||
SubTechniques: list[str]
|
||||
Description: str
|
||||
Platforms: list[str]
|
||||
TechniqueURL: str
|
||||
Attributes: list[Mitre_Requirement_Attribute]
|
||||
Checks: list[str]
|
||||
|
||||
|
||||
# Base Compliance Model
|
||||
class Compliance_Requirement(BaseModel):
|
||||
"""Compliance_Requirement holds the base model for every requirement within a compliance framework"""
|
||||
@@ -124,11 +149,11 @@ class Compliance_Requirement(BaseModel):
|
||||
Name: Optional[str]
|
||||
Attributes: list[
|
||||
Union[
|
||||
CIS_Requirements,
|
||||
ENS_Requirements,
|
||||
Generic_Compliance_Requirements,
|
||||
ISO27001_2013_Requirements,
|
||||
AWS_Well_Architected_Requirements,
|
||||
CIS_Requirement_Attribute,
|
||||
ENS_Requirement_Attribute,
|
||||
Generic_Compliance_Requirement_Attribute,
|
||||
ISO27001_2013_Requirement_Attribute,
|
||||
AWS_Well_Architected_Requirement_Attribute,
|
||||
]
|
||||
]
|
||||
Checks: list[str]
|
||||
@@ -141,7 +166,7 @@ class Compliance_Base_Model(BaseModel):
|
||||
Provider: str
|
||||
Version: Optional[str]
|
||||
Description: str
|
||||
Requirements: list[Compliance_Requirement]
|
||||
Requirements: list[Union[Mitre_Requirement, Compliance_Requirement]]
|
||||
|
||||
@root_validator(pre=True)
|
||||
# noqa: F841 - since vulture raises unused variable 'cls'
|
||||
|
||||
@@ -13,7 +13,9 @@ from prowler.lib.outputs.models import (
|
||||
Check_Output_CSV_CIS,
|
||||
Check_Output_CSV_ENS_RD2022,
|
||||
Check_Output_CSV_Generic_Compliance,
|
||||
Check_Output_MITRE_ATTACK,
|
||||
generate_csv_fields,
|
||||
unroll_list,
|
||||
)
|
||||
|
||||
|
||||
@@ -84,11 +86,9 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
elif compliance.Framework == "CIS" and "cis_" in str(
|
||||
output_options.output_modes
|
||||
):
|
||||
compliance_output = "cis_" + compliance.Version + "_aws"
|
||||
# Only with the version of CIS that was selected
|
||||
if "cis_" + compliance.Version + "_aws" in str(
|
||||
output_options.output_modes
|
||||
):
|
||||
compliance_output = "cis_" + compliance.Version + "_aws"
|
||||
if compliance_output in str(output_options.output_modes):
|
||||
for requirement in compliance.Requirements:
|
||||
requirement_description = requirement.Description
|
||||
requirement_id = requirement.Id
|
||||
@@ -158,7 +158,9 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
CheckId=finding.check_metadata.CheckID,
|
||||
)
|
||||
|
||||
csv_header = generate_csv_fields(Check_Output_CSV_AWS_Well_Architected)
|
||||
csv_header = generate_csv_fields(
|
||||
Check_Output_CSV_AWS_Well_Architected
|
||||
)
|
||||
|
||||
elif (
|
||||
compliance.Framework == "ISO27001"
|
||||
@@ -176,7 +178,7 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
for requirement in compliance.Requirements:
|
||||
requirement_description = requirement.Description
|
||||
requirement_id = requirement.Id
|
||||
requirement.Name
|
||||
requirement_name = requirement.Name
|
||||
for attribute in requirement.Attributes:
|
||||
compliance_row = Check_Output_CSV_AWS_ISO27001_2013(
|
||||
Provider=finding.check_metadata.Provider,
|
||||
@@ -185,6 +187,7 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
Region=finding.region,
|
||||
AssessmentDate=timestamp.isoformat(),
|
||||
Requirements_Id=requirement_id,
|
||||
Requirements_Name=requirement_name,
|
||||
Requirements_Description=requirement_description,
|
||||
Requirements_Attributes_Category=attribute.Category,
|
||||
Requirements_Attributes_Objetive_ID=attribute.Objetive_ID,
|
||||
@@ -196,7 +199,60 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
CheckId=finding.check_metadata.CheckID,
|
||||
)
|
||||
|
||||
csv_header = generate_csv_fields(Check_Output_CSV_AWS_ISO27001_2013)
|
||||
csv_header = generate_csv_fields(Check_Output_CSV_AWS_ISO27001_2013)
|
||||
|
||||
elif (
|
||||
compliance.Framework == "MITRE-ATTACK"
|
||||
and compliance.Version == ""
|
||||
and compliance.Provider == "AWS"
|
||||
):
|
||||
compliance_output = compliance.Framework
|
||||
if compliance.Version != "":
|
||||
compliance_output += "_" + compliance.Version
|
||||
if compliance.Provider != "":
|
||||
compliance_output += "_" + compliance.Provider
|
||||
|
||||
compliance_output = compliance_output.lower().replace("-", "_")
|
||||
if compliance_output in output_options.output_modes:
|
||||
for requirement in compliance.Requirements:
|
||||
requirement_description = requirement.Description
|
||||
requirement_id = requirement.Id
|
||||
requirement_name = requirement.Name
|
||||
attributes_aws_services = ""
|
||||
attributes_categories = ""
|
||||
attributes_values = ""
|
||||
attributes_comments = ""
|
||||
for attribute in requirement.Attributes:
|
||||
attributes_aws_services += attribute.AWSService + "\n"
|
||||
attributes_categories += attribute.Category + "\n"
|
||||
attributes_values += attribute.Value + "\n"
|
||||
attributes_comments += attribute.Comment + "\n"
|
||||
compliance_row = Check_Output_MITRE_ATTACK(
|
||||
Provider=finding.check_metadata.Provider,
|
||||
Description=compliance.Description,
|
||||
AccountId=audit_info.audited_account,
|
||||
Region=finding.region,
|
||||
AssessmentDate=timestamp.isoformat(),
|
||||
Requirements_Id=requirement_id,
|
||||
Requirements_Description=requirement_description,
|
||||
Requirements_Name=requirement_name,
|
||||
Requirements_Tactics=unroll_list(requirement.Tactics),
|
||||
Requirements_SubTechniques=unroll_list(
|
||||
requirement.SubTechniques
|
||||
),
|
||||
Requirements_Platforms=unroll_list(requirement.Platforms),
|
||||
Requirements_TechniqueURL=requirement.TechniqueURL,
|
||||
Requirements_Attributes_AWSServices=attributes_aws_services,
|
||||
Requirements_Attributes_Categories=attributes_categories,
|
||||
Requirements_Attributes_Values=attributes_values,
|
||||
Requirements_Attributes_Comments=attributes_comments,
|
||||
Status=finding.status,
|
||||
StatusExtended=finding.status_extended,
|
||||
ResourceId=finding.resource_id,
|
||||
CheckId=finding.check_metadata.CheckID,
|
||||
)
|
||||
|
||||
csv_header = generate_csv_fields(Check_Output_MITRE_ATTACK)
|
||||
|
||||
else:
|
||||
compliance_output = compliance.Framework
|
||||
@@ -230,7 +286,9 @@ def fill_compliance(output_options, finding, audit_info, file_descriptors):
|
||||
CheckId=finding.check_metadata.CheckID,
|
||||
)
|
||||
|
||||
csv_header = generate_csv_fields(Check_Output_CSV_Generic_Compliance)
|
||||
csv_header = generate_csv_fields(
|
||||
Check_Output_CSV_Generic_Compliance
|
||||
)
|
||||
|
||||
if compliance_row:
|
||||
csv_writer = DictWriter(
|
||||
@@ -309,7 +367,7 @@ def display_compliance_table(
|
||||
|
||||
# Add results to table
|
||||
for marco in sorted(marcos):
|
||||
ens_compliance_table["Proveedor"].append("aws")
|
||||
ens_compliance_table["Proveedor"].append(compliance.Provider)
|
||||
ens_compliance_table["Marco/Categoria"].append(marco)
|
||||
ens_compliance_table["Estado"].append(marcos[marco]["Estado"])
|
||||
ens_compliance_table["Opcional"].append(
|
||||
@@ -401,7 +459,7 @@ def display_compliance_table(
|
||||
# Add results to table
|
||||
sections = dict(sorted(sections.items()))
|
||||
for section in sections:
|
||||
cis_compliance_table["Provider"].append("aws")
|
||||
cis_compliance_table["Provider"].append(compliance.Provider)
|
||||
cis_compliance_table["Section"].append(section)
|
||||
if sections[section]["Level 1"]["FAIL"] > 0:
|
||||
cis_compliance_table["Level 1"].append(
|
||||
@@ -449,6 +507,77 @@ def display_compliance_table(
|
||||
print(
|
||||
f" - CSV: {output_directory}/{output_filename}_{compliance_framework}.csv\n"
|
||||
)
|
||||
elif "mitre_attack" in compliance_framework:
|
||||
tactics = {}
|
||||
mitre_compliance_table = {
|
||||
"Provider": [],
|
||||
"Tactic": [],
|
||||
"Status": [],
|
||||
}
|
||||
pass_count = fail_count = 0
|
||||
for finding in findings:
|
||||
check = bulk_checks_metadata[finding.check_metadata.CheckID]
|
||||
check_compliances = check.Compliance
|
||||
for compliance in check_compliances:
|
||||
if (
|
||||
"MITRE-ATTACK" in compliance.Framework
|
||||
and compliance.Version in compliance_framework
|
||||
):
|
||||
compliance_fm = compliance.Framework
|
||||
for requirement in compliance.Requirements:
|
||||
for tactic in requirement.Tactics:
|
||||
if tactic not in tactics:
|
||||
tactics[tactic] = {"FAIL": 0, "PASS": 0}
|
||||
if finding.status == "FAIL":
|
||||
fail_count += 1
|
||||
tactics[tactic]["FAIL"] += 1
|
||||
elif finding.status == "PASS":
|
||||
pass_count += 1
|
||||
tactics[tactic]["PASS"] += 1
|
||||
|
||||
# Add results to table
|
||||
tactics = dict(sorted(tactics.items()))
|
||||
for tactic in tactics:
|
||||
mitre_compliance_table["Provider"].append(compliance.Provider)
|
||||
mitre_compliance_table["Tactic"].append(tactic)
|
||||
if tactics[tactic]["FAIL"] > 0:
|
||||
mitre_compliance_table["Status"].append(
|
||||
f"{Fore.RED}FAIL({tactics[tactic]['FAIL']}){Style.RESET_ALL}"
|
||||
)
|
||||
else:
|
||||
mitre_compliance_table["Status"].append(
|
||||
f"{Fore.GREEN}PASS({tactics[tactic]['PASS']}){Style.RESET_ALL}"
|
||||
)
|
||||
if fail_count + pass_count < 1:
|
||||
print(
|
||||
f"\n {Style.BRIGHT}There are no resources for {Fore.YELLOW}{compliance_fm}{Style.RESET_ALL}.\n"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"\nCompliance Status of {Fore.YELLOW}{compliance_fm}{Style.RESET_ALL} Framework:"
|
||||
)
|
||||
overview_table = [
|
||||
[
|
||||
f"{Fore.RED}{round(fail_count/(fail_count+pass_count)*100, 2)}% ({fail_count}) FAIL{Style.RESET_ALL}",
|
||||
f"{Fore.GREEN}{round(pass_count/(fail_count+pass_count)*100, 2)}% ({pass_count}) PASS{Style.RESET_ALL}",
|
||||
]
|
||||
]
|
||||
print(tabulate(overview_table, tablefmt="rounded_grid"))
|
||||
print(
|
||||
f"\nFramework {Fore.YELLOW}{compliance_fm}{Style.RESET_ALL} Results:"
|
||||
)
|
||||
print(
|
||||
tabulate(
|
||||
mitre_compliance_table, headers="keys", tablefmt="rounded_grid"
|
||||
)
|
||||
)
|
||||
print(
|
||||
f"{Style.BRIGHT}* Only sections containing results appear.{Style.RESET_ALL}"
|
||||
)
|
||||
print(f"\nDetailed results of {compliance_fm} are in:")
|
||||
print(
|
||||
f" - CSV: {output_directory}/{output_filename}_{compliance_framework}.csv\n"
|
||||
)
|
||||
else:
|
||||
print(f"\nDetailed results of {compliance_framework.upper()} are in:")
|
||||
print(
|
||||
|
||||
@@ -19,6 +19,7 @@ from prowler.lib.outputs.models import (
|
||||
Check_Output_CSV_CIS,
|
||||
Check_Output_CSV_ENS_RD2022,
|
||||
Check_Output_CSV_Generic_Compliance,
|
||||
Check_Output_MITRE_ATTACK,
|
||||
Gcp_Check_Output_CSV,
|
||||
generate_csv_fields,
|
||||
)
|
||||
@@ -187,6 +188,16 @@ def fill_file_descriptors(output_modes, output_directory, output_filename, audit
|
||||
)
|
||||
file_descriptors.update({output_mode: file_descriptor})
|
||||
|
||||
elif output_mode == "mitre_attack_aws":
|
||||
filename = f"{output_directory}/{output_filename}_mitre_attack_aws{csv_file_suffix}"
|
||||
file_descriptor = initialize_file_descriptor(
|
||||
filename,
|
||||
output_mode,
|
||||
audit_info,
|
||||
Check_Output_MITRE_ATTACK,
|
||||
)
|
||||
file_descriptors.update({output_mode: file_descriptor})
|
||||
|
||||
else:
|
||||
# Generic Compliance framework
|
||||
filename = f"{output_directory}/{output_filename}_{output_mode}{csv_file_suffix}"
|
||||
|
||||
@@ -265,7 +265,7 @@ def parse_json_tags(tags: list):
|
||||
def generate_csv_fields(format: Any) -> list[str]:
|
||||
"""Generates the CSV headers for the given class"""
|
||||
csv_fields = []
|
||||
# __fields__ is alwayis available in the Pydantic's BaseModel class
|
||||
# __fields__ is always available in the Pydantic's BaseModel class
|
||||
for field in format.__dict__.get("__fields__").keys():
|
||||
csv_fields.append(field)
|
||||
return csv_fields
|
||||
@@ -487,6 +487,33 @@ class Gcp_Check_Output_JSON(Check_Output_JSON):
|
||||
super().__init__(**metadata)
|
||||
|
||||
|
||||
class Check_Output_MITRE_ATTACK(BaseModel):
|
||||
"""
|
||||
Check_Output_MITRE_ATTACK generates a finding's output in CSV MITRE ATTACK format.
|
||||
"""
|
||||
|
||||
Provider: str
|
||||
Description: str
|
||||
AccountId: str
|
||||
Region: str
|
||||
AssessmentDate: str
|
||||
Requirements_Id: str
|
||||
Requirements_Name: str
|
||||
Requirements_Description: str
|
||||
Requirements_Tactics: str
|
||||
Requirements_SubTechniques: str
|
||||
Requirements_Platforms: str
|
||||
Requirements_TechniqueURL: str
|
||||
Requirements_Attributes_AWSServices: str
|
||||
Requirements_Attributes_Categories: str
|
||||
Requirements_Attributes_Values: str
|
||||
Requirements_Attributes_Comments: str
|
||||
Status: str
|
||||
StatusExtended: str
|
||||
ResourceId: str
|
||||
CheckId: str
|
||||
|
||||
|
||||
class Check_Output_CSV_ENS_RD2022(BaseModel):
|
||||
"""
|
||||
Check_Output_CSV_ENS_RD2022 generates a finding's output in CSV ENS RD2022 format.
|
||||
|
||||
@@ -20,7 +20,7 @@ from prowler.config.config import (
|
||||
timestamp_utc,
|
||||
)
|
||||
from prowler.lib.check.compliance_models import (
|
||||
CIS_Requirements,
|
||||
CIS_Requirement_Attribute,
|
||||
Compliance_Base_Model,
|
||||
Compliance_Requirement,
|
||||
)
|
||||
@@ -1351,7 +1351,7 @@ class Test_Outputs:
|
||||
Id="2.1.3",
|
||||
Description="Ensure MFA Delete is enabled on S3 buckets",
|
||||
Attributes=[
|
||||
CIS_Requirements(
|
||||
CIS_Requirement_Attribute(
|
||||
Section="2.1. Simple Storage Service (S3)",
|
||||
Profile="Level 1",
|
||||
AssessmentStatus="Automated",
|
||||
@@ -1378,7 +1378,7 @@ class Test_Outputs:
|
||||
Id="2.1.3",
|
||||
Description="Ensure MFA Delete is enabled on S3 buckets",
|
||||
Attributes=[
|
||||
CIS_Requirements(
|
||||
CIS_Requirement_Attribute(
|
||||
Section="2.1. Simple Storage Service (S3)",
|
||||
Profile="Level 1",
|
||||
AssessmentStatus="Automated",
|
||||
|
||||
Reference in New Issue
Block a user