chore(cis): add CIS output class (#4400)

Co-authored-by: pedrooot <pedromarting3@gmail.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
This commit is contained in:
Sergio Garcia
2024-07-10 09:26:08 -04:00
committed by GitHub
parent 64b21ae2b9
commit a5a8c2a769
28 changed files with 1184 additions and 482 deletions
+72
View File
@@ -43,6 +43,10 @@ from prowler.lib.check.custom_checks_metadata import (
from prowler.lib.cli.parser import ProwlerArgumentParser
from prowler.lib.logger import logger, set_logging_config
from prowler.lib.outputs.asff.asff import ASFF
from prowler.lib.outputs.compliance.cis.cis_aws import AWSCIS
from prowler.lib.outputs.compliance.cis.cis_azure import AzureCIS
from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
from prowler.lib.outputs.compliance.compliance import display_compliance_table
from prowler.lib.outputs.csv.models import CSV
from prowler.lib.outputs.finding import Finding
@@ -350,6 +354,74 @@ def prowler():
bucket_session,
)
# Compliance Frameworks
input_compliance_frameworks = set(
global_provider.output_options.output_modes
).intersection(get_available_compliance_frameworks(provider))
if provider == "aws":
for compliance_name in input_compliance_frameworks:
if compliance_name.startswith("cis_"):
# Generate CIS Finding Object
filename = (
f"{global_provider.output_options.output_directory}/compliance/"
f"{global_provider.output_options.output_filename}_{compliance_name}.csv"
)
cis_finding = AWSCIS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
cis_finding.batch_write_data_to_file()
elif provider == "azure":
for compliance_name in input_compliance_frameworks:
if compliance_name.startswith("cis_"):
# Generate CIS Finding Object
filename = (
f"{global_provider.output_options.output_directory}/compliance/"
f"{global_provider.output_options.output_filename}_{compliance_name}.csv"
)
cis_finding = AzureCIS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
cis_finding.batch_write_data_to_file()
elif provider == "gcp":
for compliance_name in input_compliance_frameworks:
if compliance_name.startswith("cis_"):
# Generate CIS Finding Object
filename = (
f"{global_provider.output_options.output_directory}/compliance/"
f"{global_provider.output_options.output_filename}_{compliance_name}.csv"
)
cis_finding = GCPCIS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
cis_finding.batch_write_data_to_file()
elif provider == "kubernetes":
for compliance_name in input_compliance_frameworks:
if compliance_name.startswith("cis_"):
# Generate CIS Finding Object
filename = (
f"{global_provider.output_options.output_directory}/compliance/"
f"{global_provider.output_options.output_filename}_{compliance_name}.csv"
)
cis_finding = KubernetesCIS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
cis_finding.batch_write_data_to_file()
# AWS Security Hub Integration
if provider == "aws" and args.security_hub:
print(
+3 -3
View File
@@ -2,7 +2,7 @@ import sys
from pydantic import parse_obj_as
from prowler.lib.check.compliance_models import Compliance_Base_Model
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.check.models import Check_Metadata_Model
from prowler.lib.logger import logger
@@ -22,7 +22,7 @@ def update_checks_metadata_with_compliance(
# Include the requirement into the check's framework requirements
compliance_requirements.append(requirement)
# Create the Compliance_Model
compliance = Compliance_Base_Model(
compliance = ComplianceBaseModel(
Framework=framework.Framework,
Provider=framework.Provider,
Version=framework.Version,
@@ -43,7 +43,7 @@ def update_checks_metadata_with_compliance(
if not requirement.Checks:
compliance_requirements.append(requirement)
# Create the Compliance_Model
compliance = Compliance_Base_Model(
compliance = ComplianceBaseModel(
Framework=framework.Framework,
Provider=framework.Provider,
Version=framework.Version,
+4 -4
View File
@@ -189,8 +189,8 @@ class Compliance_Requirement(BaseModel):
Checks: list[str]
class Compliance_Base_Model(BaseModel):
"""Compliance_Base_Model holds the base model for every compliance framework"""
class ComplianceBaseModel(BaseModel):
"""ComplianceBaseModel holds the base model for every compliance framework"""
Framework: str
Provider: str
@@ -218,10 +218,10 @@ class Compliance_Base_Model(BaseModel):
# Testing Pending
def load_compliance_framework(
compliance_specification_file: str,
) -> Compliance_Base_Model:
) -> ComplianceBaseModel:
"""load_compliance_framework loads and parse a Compliance Framework Specification"""
try:
compliance_framework = Compliance_Base_Model.parse_file(
compliance_framework = ComplianceBaseModel.parse_file(
compliance_specification_file
)
except ValidationError as error:
@@ -2,75 +2,6 @@ from colorama import Fore, Style
from tabulate import tabulate
from prowler.config.config import orange_color
from prowler.lib.logger import logger
from prowler.lib.outputs.compliance.cis_aws import generate_compliance_row_cis_aws
from prowler.lib.outputs.compliance.cis_azure import generate_compliance_row_cis_azure
from prowler.lib.outputs.compliance.cis_gcp import generate_compliance_row_cis_gcp
from prowler.lib.outputs.compliance.cis_kubernetes import (
generate_compliance_row_cis_kubernetes,
)
from prowler.lib.outputs.csv.csv import write_csv
def write_compliance_row_cis(
file_descriptors,
finding,
compliance,
output_options,
provider,
input_compliance_frameworks,
):
try:
compliance_output = (
"cis_" + compliance.Version + "_" + compliance.Provider.lower()
)
# Only with the version of CIS that was selected
if compliance_output in str(input_compliance_frameworks):
for requirement in compliance.Requirements:
for attribute in requirement.Attributes:
if compliance.Provider == "AWS":
(compliance_row, csv_header) = generate_compliance_row_cis_aws(
finding,
compliance,
requirement,
attribute,
output_options,
provider,
)
elif compliance.Provider == "Azure":
(compliance_row, csv_header) = (
generate_compliance_row_cis_azure(
finding,
compliance,
requirement,
attribute,
output_options,
)
)
elif compliance.Provider == "GCP":
(compliance_row, csv_header) = generate_compliance_row_cis_gcp(
finding, compliance, requirement, attribute, output_options
)
elif compliance.Provider == "Kubernetes":
(compliance_row, csv_header) = (
generate_compliance_row_cis_kubernetes(
finding,
compliance,
requirement,
attribute,
output_options,
provider,
)
)
write_csv(
file_descriptors[compliance_output], csv_header, compliance_row
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def get_cis_table(
@@ -0,0 +1,99 @@
from csv import DictWriter
from venv import logger
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.outputs.compliance.cis.models import AWS
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.finding import Finding
class AWSCIS(ComplianceOutput):
"""
This class represents the AWS CIS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into AWS CIS compliance format.
- batch_write_data_to_file: Writes the findings data to a CSV file in AWS CIS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: ComplianceBaseModel,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into AWS CIS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (ComplianceBaseModel): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = AWS(
Provider=finding.provider,
Description=compliance.Description,
AccountId=finding.account_uid,
Region=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
def batch_write_data_to_file(self) -> None:
"""
Writes the findings data to a CSV file in AWS CIS compliance format.
Returns:
- None
"""
try:
if (
getattr(self, "_file_descriptor", None)
and not self._file_descriptor.closed
and self._data
):
csv_writer = DictWriter(
self._file_descriptor,
fieldnames=[field.upper() for field in self._data[0].dict().keys()],
delimiter=";",
)
csv_writer.writeheader()
for finding in self._data:
csv_writer.writerow(
{k.upper(): v for k, v in finding.dict().items()}
)
self._file_descriptor.close()
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@@ -0,0 +1,95 @@
from csv import DictWriter
from venv import logger
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.outputs.compliance.cis.models import Azure
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.finding import Finding
class AzureCIS(ComplianceOutput):
"""
This class represents the Azure CIS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into Azure CIS compliance format.
- batch_write_data_to_file: Writes the findings data to a CSV file in Azure CIS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: ComplianceBaseModel,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into Azure CIS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (ComplianceBaseModel): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = Azure(
Provider=finding.provider,
Description=compliance.Description,
Subscription=finding.account_name,
Location=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
ResourceName=finding.resource_name,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
def batch_write_data_to_file(self) -> None:
try:
if (
getattr(self, "_file_descriptor", None)
and not self._file_descriptor.closed
and self._data
):
csv_writer = DictWriter(
self._file_descriptor,
fieldnames=[field.upper() for field in self._data[0].dict().keys()],
delimiter=";",
)
csv_writer.writeheader()
for finding in self._data:
csv_writer.writerow(
{k.upper(): v for k, v in finding.dict().items()}
)
self._file_descriptor.close()
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@@ -0,0 +1,94 @@
from csv import DictWriter
from venv import logger
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.outputs.compliance.cis.models import GCP
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.finding import Finding
class GCPCIS(ComplianceOutput):
"""
This class represents the GCP CIS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into GCP CIS compliance format.
- batch_write_data_to_file: Writes the findings data to a CSV file in GCP CIS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: ComplianceBaseModel,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into GCP CIS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (ComplianceBaseModel): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = GCP(
Provider=finding.provider,
Description=compliance.Description,
ProjectId=finding.account_uid,
Location=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
ResourceName=finding.resource_name,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
def batch_write_data_to_file(self) -> None:
try:
if (
getattr(self, "_file_descriptor", None)
and not self._file_descriptor.closed
and self._data
):
csv_writer = DictWriter(
self._file_descriptor,
fieldnames=[field.upper() for field in self._data[0].dict().keys()],
delimiter=";",
)
csv_writer.writeheader()
for finding in self._data:
csv_writer.writerow(
{k.upper(): v for k, v in finding.dict().items()}
)
self._file_descriptor.close()
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@@ -0,0 +1,94 @@
from csv import DictWriter
from venv import logger
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.outputs.compliance.cis.models import Kubernetes
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.finding import Finding
class KubernetesCIS(ComplianceOutput):
"""
This class represents the Kubernetes CIS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into Kubernetes CIS compliance format.
- batch_write_data_to_file: Writes the findings data to a CSV file in Kubernetes CIS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: ComplianceBaseModel,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into Kubernetes CIS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (ComplianceBaseModel): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = Kubernetes(
Provider=finding.provider,
Description=compliance.Description,
Context=finding.account_name,
Namespace=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
def batch_write_data_to_file(self) -> None:
try:
if (
getattr(self, "_file_descriptor", None)
and not self._file_descriptor.closed
and self._data
):
csv_writer = DictWriter(
self._file_descriptor,
fieldnames=[field.upper() for field in self._data[0].dict().keys()],
delimiter=";",
)
csv_writer.writeheader()
for finding in self._data:
csv_writer.writerow(
{k.upper(): v for k, v in finding.dict().items()}
)
self._file_descriptor.close()
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@@ -0,0 +1,64 @@
from pydantic import BaseModel
class CIS(BaseModel):
"""
CIS generates a finding's output in CIS Compliance format.
"""
Provider: str
Description: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
Requirements_Attributes_RationaleStatement: str
Requirements_Attributes_ImpactStatement: str
Requirements_Attributes_RemediationProcedure: str
Requirements_Attributes_AuditProcedure: str
Requirements_Attributes_AdditionalInformation: str
Requirements_Attributes_References: str
Status: str
StatusExtended: str
ResourceId: str
CheckId: str
Muted: bool
class AWS(CIS):
"""
AWS CIS Compliance format.
"""
AccountId: str
Region: str
class Azure(CIS):
"""
Azure CIS Compliance format.
"""
Subscription: str
Location: str
class GCP(CIS):
"""
GCP CIS Compliance format.
"""
ProjectId: str
Location: str
class Kubernetes(CIS):
"""
Kubernetes CIS Compliance format.
"""
Context: str
Namespace: str
-36
View File
@@ -1,36 +0,0 @@
from prowler.config.config import timestamp
from prowler.lib.outputs.compliance.models import Check_Output_CSV_AWS_CIS
from prowler.lib.outputs.csv.csv import generate_csv_fields
from prowler.lib.utils.utils import outputs_unix_timestamp
def generate_compliance_row_cis_aws(
finding, compliance, requirement, attribute, output_options, provider
):
compliance_row = Check_Output_CSV_AWS_CIS(
Provider=finding.check_metadata.Provider,
Description=compliance.Description,
AccountId=provider.identity.account,
Region=finding.region,
AssessmentDate=outputs_unix_timestamp(output_options.unix_timestamp, timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_id,
CheckId=finding.check_metadata.CheckID,
Muted=finding.muted,
)
csv_header = generate_csv_fields(Check_Output_CSV_AWS_CIS)
return compliance_row, csv_header
@@ -1,37 +0,0 @@
from prowler.config.config import timestamp
from prowler.lib.outputs.compliance.models import Check_Output_CSV_AZURE_CIS
from prowler.lib.outputs.csv.csv import generate_csv_fields
from prowler.lib.utils.utils import outputs_unix_timestamp
def generate_compliance_row_cis_azure(
finding, compliance, requirement, attribute, output_options
):
compliance_row = Check_Output_CSV_AZURE_CIS(
Provider=finding.check_metadata.Provider,
Description=compliance.Description,
Subscription=finding.subscription,
AssessmentDate=outputs_unix_timestamp(output_options.unix_timestamp, timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_id,
ResourceName=finding.resource_name,
CheckId=finding.check_metadata.CheckID,
Muted=finding.muted,
)
csv_header = generate_csv_fields(Check_Output_CSV_AZURE_CIS)
return compliance_row, csv_header
-37
View File
@@ -1,37 +0,0 @@
from prowler.config.config import timestamp
from prowler.lib.outputs.compliance.models import Check_Output_CSV_GCP_CIS
from prowler.lib.outputs.csv.csv import generate_csv_fields
from prowler.lib.utils.utils import outputs_unix_timestamp
def generate_compliance_row_cis_gcp(
finding, compliance, requirement, attribute, output_options
):
compliance_row = Check_Output_CSV_GCP_CIS(
Provider=finding.check_metadata.Provider,
Description=compliance.Description,
ProjectId=finding.project_id,
Location=finding.location.lower(),
AssessmentDate=outputs_unix_timestamp(output_options.unix_timestamp, timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_id,
ResourceName=finding.resource_name,
CheckId=finding.check_metadata.CheckID,
Muted=finding.muted,
)
csv_header = generate_csv_fields(Check_Output_CSV_GCP_CIS)
return compliance_row, csv_header
@@ -1,37 +0,0 @@
from prowler.config.config import timestamp
from prowler.lib.outputs.compliance.models import Check_Output_CSV_KUBERNETES_CIS
from prowler.lib.outputs.csv.csv import generate_csv_fields
from prowler.lib.utils.utils import outputs_unix_timestamp
def generate_compliance_row_cis_kubernetes(
finding, compliance, requirement, attribute, output_options, provider
):
compliance_row = Check_Output_CSV_KUBERNETES_CIS(
Provider=finding.check_metadata.Provider,
Description=compliance.Description,
Context=provider.identity.context,
Namespace=finding.namespace,
AssessmentDate=outputs_unix_timestamp(output_options.unix_timestamp, timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
Requirements_Attributes_RationaleStatement=attribute.RationaleStatement,
Requirements_Attributes_ImpactStatement=attribute.ImpactStatement,
Requirements_Attributes_RemediationProcedure=attribute.RemediationProcedure,
Requirements_Attributes_AuditProcedure=attribute.AuditProcedure,
Requirements_Attributes_AdditionalInformation=attribute.AdditionalInformation,
Requirements_Attributes_References=attribute.References,
Requirements_Attributes_DefaultValue=attribute.DefaultValue,
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_id,
CheckId=finding.check_metadata.CheckID,
Muted=finding.muted,
)
csv_header = generate_csv_fields(Check_Output_CSV_KUBERNETES_CIS)
return compliance_row, csv_header
+2 -9
View File
@@ -5,7 +5,7 @@ from prowler.lib.logger import logger
from prowler.lib.outputs.compliance.aws_well_architected_framework import (
write_compliance_row_aws_well_architected_framework,
)
from prowler.lib.outputs.compliance.cis import get_cis_table, write_compliance_row_cis
from prowler.lib.outputs.compliance.cis.cis import get_cis_table
from prowler.lib.outputs.compliance.ens_rd2022_aws import (
get_ens_rd2022_aws_table,
write_compliance_row_ens_rd2022_aws,
@@ -103,14 +103,7 @@ def fill_compliance(
)
elif compliance.Framework == "CIS":
write_compliance_row_cis(
file_descriptors,
finding,
compliance,
output_options,
provider,
input_compliance_frameworks,
)
continue
elif (
"AWS-Well-Architected-Framework" in compliance.Framework
@@ -0,0 +1,46 @@
from io import TextIOWrapper
from typing import List
from prowler.lib.check.compliance_models import ComplianceBaseModel
from prowler.lib.outputs.finding import Finding
from prowler.lib.outputs.output import Output
class ComplianceOutput(Output):
"""
This class represents an abstract base class for defining different types of outputs for findings.
Attributes:
_data (list): A list to store transformed data from findings.
_file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
__init__: Initializes the Output class with findings, optionally creates a file descriptor.
data: Property to access the transformed data.
file_descriptor: Property to access the file descriptor.
transform: Abstract method to transform findings into a specific format.
batch_write_data_to_file: Abstract method to write data to a file in batches.
create_file_descriptor: Method to create a file descriptor for writing data to a file.
"""
_data: list
_file_descriptor: TextIOWrapper
def __init__(
self,
findings: List[Finding],
compliance: ComplianceBaseModel,
create_file_descriptor: bool = False,
file_path: str = None,
) -> None:
self._data = []
if findings:
# Get the compliance name of the model
compliance_name = (
compliance.Framework + "-" + compliance.Version
if compliance.Version
else compliance.Framework
)
self.transform(findings, compliance, compliance_name)
if create_file_descriptor:
self.create_file_descriptor(file_path)
-119
View File
@@ -32,125 +32,6 @@ class Check_Output_CSV_ENS_RD2022(BaseModel):
Muted: bool
class Check_Output_CSV_AWS_CIS(BaseModel):
"""
Check_Output_CSV_CIS generates a finding's output in CSV CIS format.
"""
Provider: str
Description: str
AccountId: str
Region: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
Requirements_Attributes_RationaleStatement: str
Requirements_Attributes_ImpactStatement: str
Requirements_Attributes_RemediationProcedure: str
Requirements_Attributes_AuditProcedure: str
Requirements_Attributes_AdditionalInformation: str
Requirements_Attributes_References: str
Status: str
StatusExtended: str
ResourceId: str
CheckId: str
Muted: bool
class Check_Output_CSV_AZURE_CIS(BaseModel):
"""
Check_Output_CSV_CIS generates a finding's output in CSV CIS format.
"""
Provider: str
Description: str
Subscription: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
Requirements_Attributes_RationaleStatement: str
Requirements_Attributes_ImpactStatement: str
Requirements_Attributes_RemediationProcedure: str
Requirements_Attributes_AuditProcedure: str
Requirements_Attributes_AdditionalInformation: str
Requirements_Attributes_DefaultValue: str
Requirements_Attributes_References: str
Status: str
StatusExtended: str
ResourceId: str
ResourceName: str
CheckId: str
Muted: bool
class Check_Output_CSV_GCP_CIS(BaseModel):
"""
Check_Output_CSV_CIS generates a finding's output in CSV CIS format.
"""
Provider: str
Description: str
ProjectId: str
Location: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
Requirements_Attributes_RationaleStatement: str
Requirements_Attributes_ImpactStatement: str
Requirements_Attributes_RemediationProcedure: str
Requirements_Attributes_AuditProcedure: str
Requirements_Attributes_AdditionalInformation: str
Requirements_Attributes_References: str
Status: str
StatusExtended: str
ResourceId: str
ResourceName: str
CheckId: str
Muted: bool
class Check_Output_CSV_KUBERNETES_CIS(BaseModel):
"""
Check_Output_CSV_CIS generates a finding's output in CSV CIS format.
"""
Provider: str
Description: str
Context: str
Namespace: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
Requirements_Attributes_RationaleStatement: str
Requirements_Attributes_ImpactStatement: str
Requirements_Attributes_RemediationProcedure: str
Requirements_Attributes_AuditProcedure: str
Requirements_Attributes_AdditionalInformation: str
Requirements_Attributes_References: str
Requirements_Attributes_DefaultValue: str
Status: str
StatusExtended: str
ResourceId: str
CheckId: str
Muted: bool
class Check_Output_CSV_Generic_Compliance(BaseModel):
"""
Check_Output_CSV_Generic_Compliance generates a finding's output in CSV Generic Compliance format.
+12 -47
View File
@@ -10,14 +10,10 @@ from prowler.lib.outputs.compliance.mitre_attack.models import (
MitreAttackGCP,
)
from prowler.lib.outputs.compliance.models import (
Check_Output_CSV_AWS_CIS,
Check_Output_CSV_AWS_ISO27001_2013,
Check_Output_CSV_AWS_Well_Architected,
Check_Output_CSV_AZURE_CIS,
Check_Output_CSV_ENS_RD2022,
Check_Output_CSV_GCP_CIS,
Check_Output_CSV_Generic_Compliance,
Check_Output_CSV_KUBERNETES_CIS,
)
from prowler.lib.outputs.csv.csv import generate_csv_fields
from prowler.lib.outputs.output import Finding
@@ -71,18 +67,13 @@ def fill_file_descriptors(output_modes, output_directory, output_filename, provi
continue
elif output_mode == "html":
continue
# FIXME: Remove this once we merge all the compliance frameworks
if "cis_" in output_mode:
continue
elif provider.type == "gcp":
filename = f"{output_directory}/compliance/{output_filename}_{output_mode}{csv_file_suffix}"
if "cis_" in output_mode:
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_GCP_CIS,
)
file_descriptors.update({output_mode: file_descriptor})
elif output_mode == "mitre_attack_gcp":
if output_mode == "mitre_attack_gcp":
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
@@ -101,34 +92,17 @@ def fill_file_descriptors(output_modes, output_directory, output_filename, provi
elif provider.type == "kubernetes":
filename = f"{output_directory}/compliance/{output_filename}_{output_mode}{csv_file_suffix}"
if "cis_" in output_mode:
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_KUBERNETES_CIS,
)
file_descriptors.update({output_mode: file_descriptor})
else:
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_Generic_Compliance,
)
file_descriptors.update({output_mode: file_descriptor})
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_Generic_Compliance,
)
file_descriptors.update({output_mode: file_descriptor})
elif provider.type == "azure":
filename = f"{output_directory}/compliance/{output_filename}_{output_mode}{csv_file_suffix}"
if "cis_" in output_mode:
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_AZURE_CIS,
)
file_descriptors.update({output_mode: file_descriptor})
elif output_mode == "mitre_attack_azure":
if output_mode == "mitre_attack_azure":
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
@@ -157,15 +131,6 @@ def fill_file_descriptors(output_modes, output_directory, output_filename, provi
)
file_descriptors.update({output_mode: file_descriptor})
elif "cis_" in output_mode:
file_descriptor = initialize_file_descriptor(
filename,
output_mode,
provider.type,
Check_Output_CSV_AWS_CIS,
)
file_descriptors.update({output_mode: file_descriptor})
elif "aws_well_architected_framework" in output_mode:
file_descriptor = initialize_file_descriptor(
filename,
+2 -2
View File
@@ -3,8 +3,8 @@ from prowler.lib.check.compliance_models import (
CIS_Requirement_Attribute,
CIS_Requirement_Attribute_AssessmentStatus,
CIS_Requirement_Attribute_Profile,
Compliance_Base_Model,
Compliance_Requirement,
ComplianceBaseModel,
)
from prowler.lib.check.models import Check_Metadata_Model
@@ -14,7 +14,7 @@ class TestCompliance:
def get_custom_framework(self):
return {
"framework1": Compliance_Base_Model(
"framework1": ComplianceBaseModel(
Framework="Framework1",
Provider="Provider1",
Version="1.0",
@@ -0,0 +1,90 @@
from datetime import datetime
from io import StringIO
from freezegun import freeze_time
from mock import patch
from prowler.lib.outputs.compliance.cis.cis_aws import AWSCIS
from prowler.lib.outputs.compliance.cis.models import AWS
from tests.lib.outputs.compliance.fixtures import CIS_1_4_AWS
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1
class TestAWSCIS:
def test_output_transform(self):
findings = [generate_finding_output(compliance={"CIS-1.4": "2.1.3"})]
output = AWSCIS(findings, CIS_1_4_AWS)
output_data = output.data[0]
assert isinstance(output_data, AWS)
assert output_data.Provider == "aws"
assert output_data.AccountId == AWS_ACCOUNT_NUMBER
assert output_data.Region == AWS_REGION_EU_WEST_1
assert output_data.Description == CIS_1_4_AWS.Description
assert output_data.Requirements_Id == CIS_1_4_AWS.Requirements[0].Id
assert (
output_data.Requirements_Description
== CIS_1_4_AWS.Requirements[0].Description
)
assert (
output_data.Requirements_Attributes_Section
== CIS_1_4_AWS.Requirements[0].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_Profile
== CIS_1_4_AWS.Requirements[0].Attributes[0].Profile
)
assert (
output_data.Requirements_Attributes_AssessmentStatus
== CIS_1_4_AWS.Requirements[0].Attributes[0].AssessmentStatus
)
assert (
output_data.Requirements_Attributes_Description
== CIS_1_4_AWS.Requirements[0].Attributes[0].Description
)
assert (
output_data.Requirements_Attributes_RationaleStatement
== CIS_1_4_AWS.Requirements[0].Attributes[0].RationaleStatement
)
assert (
output_data.Requirements_Attributes_ImpactStatement
== CIS_1_4_AWS.Requirements[0].Attributes[0].ImpactStatement
)
assert (
output_data.Requirements_Attributes_RemediationProcedure
== CIS_1_4_AWS.Requirements[0].Attributes[0].RemediationProcedure
)
assert (
output_data.Requirements_Attributes_AuditProcedure
== CIS_1_4_AWS.Requirements[0].Attributes[0].AuditProcedure
)
assert (
output_data.Requirements_Attributes_AdditionalInformation
== CIS_1_4_AWS.Requirements[0].Attributes[0].AdditionalInformation
)
assert (
output_data.Requirements_Attributes_References
== CIS_1_4_AWS.Requirements[0].Attributes[0].References
)
assert output_data.Status == "PASS"
assert output_data.StatusExtended == ""
assert output_data.ResourceId == ""
assert output_data.CheckId == "test-check-id"
assert output_data.Muted is False
@freeze_time(datetime.now())
def test_batch_write_data_to_file(self):
mock_file = StringIO()
findings = [generate_finding_output(compliance={"CIS-1.4": "2.1.3"})]
# Clear the data from CSV class
output = AWSCIS(findings, CIS_1_4_AWS)
output._file_descriptor = mock_file
with patch.object(mock_file, "close", return_value=None):
output.batch_write_data_to_file()
mock_file.seek(0)
content = mock_file.read()
expected_csv = f"""PROVIDER;DESCRIPTION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;CHECKID;MUTED;ACCOUNTID;REGION\r\naws;The CIS Benchmark for CIS Amazon Web Services Foundations Benchmark, v1.4.0, Level 1 and 2 provides prescriptive guidance for configuring security options for a subset of Amazon Web Services. It has an emphasis on foundational, testable, and architecture agnostic settings;{datetime.now()};2.1.3;Ensure MFA Delete is enabled on S3 buckets;2.1. Simple Storage Service (S3);Level 1;Automated;Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.;Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.;;"Perform the steps below to enable MFA delete on an S3 bucket.\n\nNote:\n-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.\n-You must use your \'root\' account to enable MFA Delete on S3 buckets.\n\n**From Command line:**\n\n1. Run the s3api put-bucket-versioning command\n\n```\naws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode”\n```";"Perform the steps below to confirm MFA delete is configured on an S3 Bucket\n\n**From Console:**\n\n1. Login to the S3 console at `https://console.aws.amazon.com/s3/`\n\n2. Click the `Check` box next to the Bucket name you want to confirm\n\n3. In the window under `Properties`\n\n4. Confirm that Versioning is `Enabled`\n\n5. Confirm that MFA Delete is `Enabled`\n\n**From Command Line:**\n\n1. Run the `get-bucket-versioning`\n```\naws s3api get-bucket-versioning --bucket my-bucket\n```\n\nOutput example:\n```\n<VersioningConfiguration xmlns=""http://s3.amazonaws.com/doc/2006-03-01/""> \n <Status>Enabled</Status>\n <MfaDelete>Enabled</MfaDelete> \n</VersioningConfiguration>\n```\n\nIf the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.";;https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html;PASS;;;test-check-id;False;123456789012;eu-west-1\r\n"""
assert content == expected_csv
@@ -0,0 +1,113 @@
from datetime import datetime
from io import StringIO
from freezegun import freeze_time
from mock import patch
from prowler.lib.outputs.compliance.cis.cis_azure import AzureCIS
from prowler.lib.outputs.compliance.cis.models import Azure
from tests.lib.outputs.compliance.fixtures import CIS_2_0_AZURE
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
AZURE_SUBSCRIPTION_NAME,
)
class TestAzureCIS:
def test_output_transform(self):
findings = [
generate_finding_output(
provider="azure",
compliance={"CIS-2.0": "2.1.3"},
account_name=AZURE_SUBSCRIPTION_NAME,
account_uid=AZURE_SUBSCRIPTION_ID,
region="",
)
]
output = AzureCIS(findings, CIS_2_0_AZURE)
output_data = output.data[0]
assert isinstance(output_data, Azure)
assert output_data.Provider == "azure"
assert output_data.Subscription == AZURE_SUBSCRIPTION_NAME
assert output_data.Location == ""
assert output_data.Description == CIS_2_0_AZURE.Description
assert output_data.Requirements_Id == CIS_2_0_AZURE.Requirements[0].Id
assert (
output_data.Requirements_Description
== CIS_2_0_AZURE.Requirements[0].Description
)
assert (
output_data.Requirements_Attributes_Section
== CIS_2_0_AZURE.Requirements[0].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_Profile
== CIS_2_0_AZURE.Requirements[0].Attributes[0].Profile
)
assert (
output_data.Requirements_Attributes_AssessmentStatus
== CIS_2_0_AZURE.Requirements[0].Attributes[0].AssessmentStatus
)
assert (
output_data.Requirements_Attributes_Description
== CIS_2_0_AZURE.Requirements[0].Attributes[0].Description
)
assert (
output_data.Requirements_Attributes_RationaleStatement
== CIS_2_0_AZURE.Requirements[0].Attributes[0].RationaleStatement
)
assert (
output_data.Requirements_Attributes_ImpactStatement
== CIS_2_0_AZURE.Requirements[0].Attributes[0].ImpactStatement
)
assert (
output_data.Requirements_Attributes_RemediationProcedure
== CIS_2_0_AZURE.Requirements[0].Attributes[0].RemediationProcedure
)
assert (
output_data.Requirements_Attributes_AuditProcedure
== CIS_2_0_AZURE.Requirements[0].Attributes[0].AuditProcedure
)
assert (
output_data.Requirements_Attributes_AdditionalInformation
== CIS_2_0_AZURE.Requirements[0].Attributes[0].AdditionalInformation
)
assert (
output_data.Requirements_Attributes_References
== CIS_2_0_AZURE.Requirements[0].Attributes[0].References
)
assert output_data.Status == "PASS"
assert output_data.StatusExtended == ""
assert output_data.ResourceId == ""
assert output_data.CheckId == "test-check-id"
assert output_data.Muted is False
@freeze_time(datetime.now())
def test_batch_write_data_to_file(self):
mock_file = StringIO()
findings = [
generate_finding_output(
provider="azure",
compliance={"CIS-2.0": "2.1.3"},
account_name=AZURE_SUBSCRIPTION_NAME,
account_uid=AZURE_SUBSCRIPTION_ID,
region="",
)
]
# Clear the data from CSV class
output = AzureCIS(findings, CIS_2_0_AZURE)
output._file_descriptor = mock_file
with patch.object(mock_file, "close", return_value=None):
output.batch_write_data_to_file()
mock_file.seek(0)
content = mock_file.read()
expected_csv = (
"PROVIDER;DESCRIPTION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;CHECKID;MUTED;SUBSCRIPTION;LOCATION\r\nazure;The CIS Azure Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Azure with an emphasis on foundational, testable, and architecture agnostic settings.;"
+ str(datetime.now())
+ ";2.1.3;Ensure That Microsoft Defender for Databases Is Set To 'On';2.1 Microsoft Defender for Cloud;Level 2;Manual;Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases.;Enabling Microsoft Defender for Azure SQL Databases allows your organization more granular control of the infrastructure running your database software. Instead of waiting on Microsoft release updates or other similar processes, you can manage them yourself. Threat detection is provided by the Microsoft Security Response Center (MSRC).;Running Defender on Infrastructure as a service (IaaS) may incur increased costs associated with running the service and the instance it is on. Similarly, you will need qualified personnel to maintain the operating system and software updates. If it is not maintained, security patches will not be applied and it may be open to vulnerabilities.;From Azure Portal 1. Go to Microsoft Defender for Cloud 2. Select Environment Settings 3. Click on the subscription name 4. Select Defender plans 5. Set Databases Status to On 6. Select Save Review the chosen pricing tier. For the Azure Databases resource review the different plan information and choose one that fits the needs of your organization. From Azure CLI Run the following commands: az security pricing create -n 'SqlServers' --tier 'Standard' az security pricing create -n 'SqlServerVirtualMachines' --tier 'Standard' az security pricing create -n 'OpenSourceRelationalDatabases' --tier 'Standard' az security pricing create -n 'CosmosDbs' --tier 'Standard' From Azure PowerShell Run the following commands: Set-AzSecurityPricing -Name 'SqlServers' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'SqlServerVirtualMachines' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'OpenSourceRelationalDatabases' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'CosmosDbs' -PricingTier 'Standard';From Azure Portal 1. Go to Microsoft Defender for Cloud 2. Select Environment Settings 3. Click on the subscription name 4. Select Defender plans 5. Ensure Databases Status is set to On 6. Review the chosen pricing tier From Azure CLI Ensure the output of the below commands is Standard az security pricing show -n 'SqlServers' az security pricing show -n 'SqlServerVirtualMachines' az security pricing show -n 'OpenSourceRelationalDatabases' az security pricing show -n 'CosmosDbs' If the output of any of the above commands shows pricingTier with a value of Free, the setting is out of compliance. From PowerShell Connect-AzAccount Get-AzSecurityPricing |select-object Name,PricingTier |where-object {$_.Name -match 'Sql' -or $_.Name -match 'Cosmos' -or $_.Name -match 'OpenSource'} Ensure the output shows Standard for each database type under the PricingTier column. Any that show Free are considered out of compliance.;;https://docs.microsoft.com/en-us/azure/azure-sql/database/azure-defender-for-sql?view=azuresql:https://docs.microsoft.com/en-us/azure/defender-for-cloud/quickstart-enable-database-protections:https://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-databases-usage:https://docs.microsoft.com/en-us/azure/security-center/security-center-detection-capabilities:https://docs.microsoft.com/en-us/rest/api/securitycenter/pricings/list:https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-logging-threat-detection#lt-1-enable-threat-detection-capabilities;PASS;;;test-check-id;False;Subscription Name;\r\n"
)
assert content == expected_csv
@@ -0,0 +1,106 @@
from datetime import datetime
from io import StringIO
from freezegun import freeze_time
from mock import patch
from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS
from prowler.lib.outputs.compliance.cis.models import GCP
from tests.lib.outputs.compliance.fixtures import CIS_2_0_GCP
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
from tests.providers.gcp.gcp_fixtures import GCP_PROJECT_ID
class TestGCPCIS:
def test_output_transform(self):
findings = [
generate_finding_output(
provider="gcp",
compliance={"CIS-2.0": "2.13"},
account_name=GCP_PROJECT_ID,
account_uid=GCP_PROJECT_ID,
region="",
)
]
output = GCPCIS(findings, CIS_2_0_GCP)
output_data = output.data[0]
assert isinstance(output_data, GCP)
assert output_data.Provider == "gcp"
assert output_data.ProjectId == GCP_PROJECT_ID
assert output_data.Location == ""
assert output_data.Description == CIS_2_0_GCP.Description
assert output_data.Requirements_Id == CIS_2_0_GCP.Requirements[0].Id
assert (
output_data.Requirements_Description
== CIS_2_0_GCP.Requirements[0].Description
)
assert (
output_data.Requirements_Attributes_Section
== CIS_2_0_GCP.Requirements[0].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_Profile
== CIS_2_0_GCP.Requirements[0].Attributes[0].Profile
)
assert (
output_data.Requirements_Attributes_AssessmentStatus
== CIS_2_0_GCP.Requirements[0].Attributes[0].AssessmentStatus
)
assert (
output_data.Requirements_Attributes_Description
== CIS_2_0_GCP.Requirements[0].Attributes[0].Description
)
assert (
output_data.Requirements_Attributes_RationaleStatement
== CIS_2_0_GCP.Requirements[0].Attributes[0].RationaleStatement
)
assert (
output_data.Requirements_Attributes_ImpactStatement
== CIS_2_0_GCP.Requirements[0].Attributes[0].ImpactStatement
)
assert (
output_data.Requirements_Attributes_RemediationProcedure
== CIS_2_0_GCP.Requirements[0].Attributes[0].RemediationProcedure
)
assert (
output_data.Requirements_Attributes_AuditProcedure
== CIS_2_0_GCP.Requirements[0].Attributes[0].AuditProcedure
)
assert (
output_data.Requirements_Attributes_AdditionalInformation
== CIS_2_0_GCP.Requirements[0].Attributes[0].AdditionalInformation
)
assert (
output_data.Requirements_Attributes_References
== CIS_2_0_GCP.Requirements[0].Attributes[0].References
)
assert output_data.Status == "PASS"
assert output_data.StatusExtended == ""
assert output_data.ResourceId == ""
assert output_data.CheckId == "test-check-id"
assert output_data.Muted is False
@freeze_time(datetime.now())
def test_batch_write_data_to_file(self):
mock_file = StringIO()
findings = [
generate_finding_output(
provider="gcp",
compliance={"CIS-2.0": "2.13"},
account_name=GCP_PROJECT_ID,
account_uid=GCP_PROJECT_ID,
region="",
)
]
# Clear the data from CSV class
output = GCPCIS(findings, CIS_2_0_GCP)
output._file_descriptor = mock_file
with patch.object(mock_file, "close", return_value=None):
output.batch_write_data_to_file()
mock_file.seek(0)
content = mock_file.read()
expected_csv = f"PROVIDER;DESCRIPTION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;CHECKID;MUTED;PROJECTID;LOCATION\r\ngcp;This CIS Benchmark is the product of a community consensus process and consists of secure configuration guidelines developed for Google Cloud Computing Platform;{datetime.now()};2.13;Ensure That Microsoft Defender for Databases Is Set To 'On';2. Logging and Monitoring;Level 1;Automated;GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.;The GCP resources and IAM policies captured by GCP Cloud Asset Inventory enables security analysis, resource change tracking, and compliance auditing. It is recommended GCP Cloud Asset Inventory be enabled for all GCP projects.;;**From Google Cloud Console** Enable the Cloud Asset API: 1. Go to `API & Services/Library` by visiting https://console.cloud.google.com/apis/library(https://console.cloud.google.com/apis/library) 2. Search for `Cloud Asset API` and select the result for _Cloud Asset API_ 3. Click the `ENABLE` button. **From Google Cloud CLI** Enable the Cloud Asset API: 1. Enable the Cloud Asset API through the services interface: ``` gcloud services enable cloudasset.googleapis.com ```;**From Google Cloud Console** Ensure that the Cloud Asset API is enabled: 1. Go to `API & Services/Library` by visiting https://console.cloud.google.com/apis/library(https://console.cloud.google.com/apis/library) 2. Search for `Cloud Asset API` and select the result for _Cloud Asset API_ 3. Ensure that `API Enabled` is displayed. **From Google Cloud CLI** Ensure that the Cloud Asset API is enabled: 1. Query enabled services: ``` gcloud services list --enabled --filter=name:cloudasset.googleapis.com ``` If the API is listed, then it is enabled. If the response is `Listed 0 items` the API is not enabled.;Additional info - Cloud Asset Inventory only keeps a five-week history of Google Cloud asset metadata. If a longer history is desired, automation to export the history to Cloud Storage or BigQuery should be evaluated.;https://cloud.google.com/asset-inventory/docs;PASS;;;test-check-id;False;123456789012;\r\n"
assert content == expected_csv
@@ -0,0 +1,109 @@
from datetime import datetime
from io import StringIO
from freezegun import freeze_time
from mock import patch
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
from prowler.lib.outputs.compliance.cis.models import Kubernetes
from tests.lib.outputs.compliance.fixtures import CIS_1_8_KUBERNETES
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
from tests.providers.kubernetes.kubernetes_fixtures import (
KUBERNETES_CLUSTER_NAME,
KUBERNETES_NAMESPACE,
)
class TestKubernetesCIS:
def test_output_transform(self):
findings = [
generate_finding_output(
provider="kubernetes",
compliance={"CIS-1.8": "1.1.3"},
account_name=KUBERNETES_CLUSTER_NAME,
account_uid=KUBERNETES_CLUSTER_NAME,
region=KUBERNETES_NAMESPACE,
)
]
output = KubernetesCIS(findings, CIS_1_8_KUBERNETES)
output_data = output.data[0]
assert isinstance(output_data, Kubernetes)
assert output_data.Provider == "kubernetes"
assert output_data.Context == KUBERNETES_CLUSTER_NAME
assert output_data.Namespace == KUBERNETES_NAMESPACE
assert output_data.Description == CIS_1_8_KUBERNETES.Description
assert output_data.Requirements_Id == CIS_1_8_KUBERNETES.Requirements[0].Id
assert (
output_data.Requirements_Description
== CIS_1_8_KUBERNETES.Requirements[0].Description
)
assert (
output_data.Requirements_Attributes_Section
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_Profile
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].Profile
)
assert (
output_data.Requirements_Attributes_AssessmentStatus
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].AssessmentStatus
)
assert (
output_data.Requirements_Attributes_Description
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].Description
)
assert (
output_data.Requirements_Attributes_RationaleStatement
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].RationaleStatement
)
assert (
output_data.Requirements_Attributes_ImpactStatement
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].ImpactStatement
)
assert (
output_data.Requirements_Attributes_RemediationProcedure
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].RemediationProcedure
)
assert (
output_data.Requirements_Attributes_AuditProcedure
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].AuditProcedure
)
assert (
output_data.Requirements_Attributes_AdditionalInformation
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].AdditionalInformation
)
assert (
output_data.Requirements_Attributes_References
== CIS_1_8_KUBERNETES.Requirements[0].Attributes[0].References
)
assert output_data.Status == "PASS"
assert output_data.StatusExtended == ""
assert output_data.ResourceId == ""
assert output_data.CheckId == "test-check-id"
assert output_data.Muted is False
@freeze_time(datetime.now())
def test_batch_write_data_to_file(self):
mock_file = StringIO()
findings = [
generate_finding_output(
provider="kubernetes",
compliance={"CIS-1.8": "1.1.3"},
account_name=KUBERNETES_CLUSTER_NAME,
account_uid=KUBERNETES_CLUSTER_NAME,
region=KUBERNETES_NAMESPACE,
)
]
# Clear the data from CSV class
output = KubernetesCIS(findings, CIS_1_8_KUBERNETES)
output._file_descriptor = mock_file
with patch.object(mock_file, "close", return_value=None):
output.batch_write_data_to_file()
mock_file.seek(0)
content = mock_file.read()
expected_csv = f"PROVIDER;DESCRIPTION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;CHECKID;MUTED;CONTEXT;NAMESPACE\r\nkubernetes;This CIS Kubernetes Benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes v1.27.;{datetime.now()};1.1.3;Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive;1.1 Control Plane Node Configuration Files;Level 1 - Master Node;Automated;Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.;The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.;;Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```;Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the permissions are `600` or more restrictive.;;https://kubernetes.io/docs/admin/kube-apiserver/;PASS;;;test-check-id;False;test-cluster;test-namespace\r\n"
assert content == expected_csv
@@ -1,78 +1,14 @@
from mock import MagicMock
from prowler.lib.check.compliance_models import (
CIS_Requirement_Attribute,
Compliance_Base_Model,
Compliance_Requirement,
)
from prowler.lib.outputs.compliance.compliance import (
get_check_compliance_frameworks_in_input,
)
CIS_1_4_AWS_NAME = "cis_1.4_aws"
CIS_1_4_AWS = Compliance_Base_Model(
Framework="CIS",
Provider="AWS",
Version="1.4",
Description="The CIS Benchmark for CIS Amazon Web Services Foundations Benchmark, v1.4.0, Level 1 and 2 provides prescriptive guidance for configuring security options for a subset of Amazon Web Services. It has an emphasis on foundational, testable, and architecture agnostic settings",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.1.3",
Description="Ensure MFA Delete is enabled on S3 buckets",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1. Simple Storage Service (S3)",
Profile="Level 1",
AssessmentStatus="Automated",
Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
ImpactStatement="",
RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.\n\nNote:\n-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.\n-You must use your 'root' account to enable MFA Delete on S3 buckets.\n\n**From Command line:**\n\n1. Run the s3api put-bucket-versioning command\n\n```\naws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode”\n```",
AuditProcedure='Perform the steps below to confirm MFA delete is configured on an S3 Bucket\n\n**From Console:**\n\n1. Login to the S3 console at `https://console.aws.amazon.com/s3/`\n\n2. Click the `Check` box next to the Bucket name you want to confirm\n\n3. In the window under `Properties`\n\n4. Confirm that Versioning is `Enabled`\n\n5. Confirm that MFA Delete is `Enabled`\n\n**From Command Line:**\n\n1. Run the `get-bucket-versioning`\n```\naws s3api get-bucket-versioning --bucket my-bucket\n```\n\nOutput example:\n```\n<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> \n <Status>Enabled</Status>\n <MfaDelete>Enabled</MfaDelete> \n</VersioningConfiguration>\n```\n\nIf the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.',
AdditionalInformation="",
References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
)
],
)
],
)
CIS_1_5_AWS_NAME = "cis_1.5_aws"
CIS_1_5_AWS = Compliance_Base_Model(
Framework="CIS",
Provider="AWS",
Version="1.5",
Description="The CIS Amazon Web Services Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Amazon Web Services with an emphasis on foundational, testable, and architecture agnostic settings.",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.1.3",
Description="Ensure MFA Delete is enabled on S3 buckets",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1. Simple Storage Service (S3)",
Profile="Level 1",
AssessmentStatus="Automated",
Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
ImpactStatement="",
RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.\n\nNote:\n-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.\n-You must use your 'root' account to enable MFA Delete on S3 buckets.\n\n**From Command line:**\n\n1. Run the s3api put-bucket-versioning command\n\n```\naws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode”\n```",
AuditProcedure='Perform the steps below to confirm MFA delete is configured on an S3 Bucket\n\n**From Console:**\n\n1. Login to the S3 console at `https://console.aws.amazon.com/s3/`\n\n2. Click the `Check` box next to the Bucket name you want to confirm\n\n3. In the window under `Properties`\n\n4. Confirm that Versioning is `Enabled`\n\n5. Confirm that MFA Delete is `Enabled`\n\n**From Command Line:**\n\n1. Run the `get-bucket-versioning`\n```\naws s3api get-bucket-versioning --bucket my-bucket\n```\n\nOutput example:\n```\n<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> \n <Status>Enabled</Status>\n <MfaDelete>Enabled</MfaDelete> \n</VersioningConfiguration>\n```\n\nIf the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.',
AdditionalInformation="",
References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
)
],
)
],
)
NOT_PRESENT_COMPLIANCE_NAME = "not_present_compliance_name"
NOT_PRESENT_COMPLIANCE = Compliance_Base_Model(
Framework="NOT_EXISTENT",
Provider="NOT_EXISTENT",
Version="NOT_EXISTENT",
Description="NOT_EXISTENT",
Requirements=[],
from tests.lib.outputs.compliance.fixtures import (
CIS_1_4_AWS,
CIS_1_4_AWS_NAME,
CIS_1_5_AWS,
CIS_1_5_AWS_NAME,
NOT_PRESENT_COMPLIANCE,
)
+157
View File
@@ -0,0 +1,157 @@
from prowler.lib.check.compliance_models import (
CIS_Requirement_Attribute,
Compliance_Requirement,
ComplianceBaseModel,
)
CIS_1_4_AWS_NAME = "cis_1.4_aws"
CIS_1_4_AWS = ComplianceBaseModel(
Framework="CIS",
Provider="AWS",
Version="1.4",
Description="The CIS Benchmark for CIS Amazon Web Services Foundations Benchmark, v1.4.0, Level 1 and 2 provides prescriptive guidance for configuring security options for a subset of Amazon Web Services. It has an emphasis on foundational, testable, and architecture agnostic settings",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.1.3",
Description="Ensure MFA Delete is enabled on S3 buckets",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1. Simple Storage Service (S3)",
Profile="Level 1",
AssessmentStatus="Automated",
Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
ImpactStatement="",
RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.\n\nNote:\n-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.\n-You must use your 'root' account to enable MFA Delete on S3 buckets.\n\n**From Command line:**\n\n1. Run the s3api put-bucket-versioning command\n\n```\naws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode”\n```",
AuditProcedure='Perform the steps below to confirm MFA delete is configured on an S3 Bucket\n\n**From Console:**\n\n1. Login to the S3 console at `https://console.aws.amazon.com/s3/`\n\n2. Click the `Check` box next to the Bucket name you want to confirm\n\n3. In the window under `Properties`\n\n4. Confirm that Versioning is `Enabled`\n\n5. Confirm that MFA Delete is `Enabled`\n\n**From Command Line:**\n\n1. Run the `get-bucket-versioning`\n```\naws s3api get-bucket-versioning --bucket my-bucket\n```\n\nOutput example:\n```\n<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> \n <Status>Enabled</Status>\n <MfaDelete>Enabled</MfaDelete> \n</VersioningConfiguration>\n```\n\nIf the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.',
AdditionalInformation="",
References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
)
],
)
],
)
CIS_2_0_AZURE_NAME = "cis_2.0_azure"
CIS_2_0_AZURE = ComplianceBaseModel(
Framework="CIS",
Provider="Azure",
Version="2.0",
Description="The CIS Azure Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Azure with an emphasis on foundational, testable, and architecture agnostic settings.",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.1.3",
Description="Ensure That Microsoft Defender for Databases Is Set To 'On'",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1 Microsoft Defender for Cloud",
Profile="Level 2",
AssessmentStatus="Manual",
Description="Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases.",
RationaleStatement="Enabling Microsoft Defender for Azure SQL Databases allows your organization more granular control of the infrastructure running your database software. Instead of waiting on Microsoft release updates or other similar processes, you can manage them yourself. Threat detection is provided by the Microsoft Security Response Center (MSRC).",
ImpactStatement="Running Defender on Infrastructure as a service (IaaS) may incur increased costs associated with running the service and the instance it is on. Similarly, you will need qualified personnel to maintain the operating system and software updates. If it is not maintained, security patches will not be applied and it may be open to vulnerabilities.",
RemediationProcedure="From Azure Portal 1. Go to Microsoft Defender for Cloud 2. Select Environment Settings 3. Click on the subscription name 4. Select Defender plans 5. Set Databases Status to On 6. Select Save Review the chosen pricing tier. For the Azure Databases resource review the different plan information and choose one that fits the needs of your organization. From Azure CLI Run the following commands: az security pricing create -n 'SqlServers' --tier 'Standard' az security pricing create -n 'SqlServerVirtualMachines' --tier 'Standard' az security pricing create -n 'OpenSourceRelationalDatabases' --tier 'Standard' az security pricing create -n 'CosmosDbs' --tier 'Standard' From Azure PowerShell Run the following commands: Set-AzSecurityPricing -Name 'SqlServers' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'SqlServerVirtualMachines' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'OpenSourceRelationalDatabases' -PricingTier 'Standard' Set-AzSecurityPricing -Name 'CosmosDbs' -PricingTier 'Standard'",
AuditProcedure="From Azure Portal 1. Go to Microsoft Defender for Cloud 2. Select Environment Settings 3. Click on the subscription name 4. Select Defender plans 5. Ensure Databases Status is set to On 6. Review the chosen pricing tier From Azure CLI Ensure the output of the below commands is Standard az security pricing show -n 'SqlServers' az security pricing show -n 'SqlServerVirtualMachines' az security pricing show -n 'OpenSourceRelationalDatabases' az security pricing show -n 'CosmosDbs' If the output of any of the above commands shows pricingTier with a value of Free, the setting is out of compliance. From PowerShell Connect-AzAccount Get-AzSecurityPricing |select-object Name,PricingTier |where-object {$_.Name -match 'Sql' -or $_.Name -match 'Cosmos' -or $_.Name -match 'OpenSource'} Ensure the output shows Standard for each database type under the PricingTier column. Any that show Free are considered out of compliance.",
AdditionalInformation="",
DefaultValue="By default, Microsoft Defender plan is off.",
References="https://docs.microsoft.com/en-us/azure/azure-sql/database/azure-defender-for-sql?view=azuresql:https://docs.microsoft.com/en-us/azure/defender-for-cloud/quickstart-enable-database-protections:https://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-databases-usage:https://docs.microsoft.com/en-us/azure/security-center/security-center-detection-capabilities:https://docs.microsoft.com/en-us/rest/api/securitycenter/pricings/list:https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-logging-threat-detection#lt-1-enable-threat-detection-capabilities",
)
],
)
],
)
CIS_2_0_GCP_NAME = "cis_2.0_gcp"
CIS_2_0_GCP = ComplianceBaseModel(
Framework="CIS",
Provider="GCP",
Version="2.0",
Description="This CIS Benchmark is the product of a community consensus process and consists of secure configuration guidelines developed for Google Cloud Computing Platform",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.13",
Description="Ensure That Microsoft Defender for Databases Is Set To 'On'",
Attributes=[
CIS_Requirement_Attribute(
Section="2. Logging and Monitoring",
Profile="Level 1",
AssessmentStatus="Automated",
Description="GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.",
RationaleStatement="The GCP resources and IAM policies captured by GCP Cloud Asset Inventory enables security analysis, resource change tracking, and compliance auditing. It is recommended GCP Cloud Asset Inventory be enabled for all GCP projects.",
ImpactStatement="",
RemediationProcedure="**From Google Cloud Console** Enable the Cloud Asset API: 1. Go to `API & Services/Library` by visiting https://console.cloud.google.com/apis/library(https://console.cloud.google.com/apis/library) 2. Search for `Cloud Asset API` and select the result for _Cloud Asset API_ 3. Click the `ENABLE` button. **From Google Cloud CLI** Enable the Cloud Asset API: 1. Enable the Cloud Asset API through the services interface: ``` gcloud services enable cloudasset.googleapis.com ```",
AuditProcedure="**From Google Cloud Console** Ensure that the Cloud Asset API is enabled: 1. Go to `API & Services/Library` by visiting https://console.cloud.google.com/apis/library(https://console.cloud.google.com/apis/library) 2. Search for `Cloud Asset API` and select the result for _Cloud Asset API_ 3. Ensure that `API Enabled` is displayed. **From Google Cloud CLI** Ensure that the Cloud Asset API is enabled: 1. Query enabled services: ``` gcloud services list --enabled --filter=name:cloudasset.googleapis.com ``` If the API is listed, then it is enabled. If the response is `Listed 0 items` the API is not enabled.",
AdditionalInformation="Additional info - Cloud Asset Inventory only keeps a five-week history of Google Cloud asset metadata. If a longer history is desired, automation to export the history to Cloud Storage or BigQuery should be evaluated.",
References="https://cloud.google.com/asset-inventory/docs",
)
],
)
],
)
CIS_1_8_KUBERNETES_NAME = "cis_2.0_kubernetes"
CIS_1_8_KUBERNETES = ComplianceBaseModel(
Framework="CIS",
Provider="Kubernetes",
Version="1.8",
Description="This CIS Kubernetes Benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes v1.27.",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="1.1.3",
Description="Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive",
Attributes=[
CIS_Requirement_Attribute(
Section="1.1 Control Plane Node Configuration Files",
Profile="Level 1 - Master Node",
AssessmentStatus="Automated",
Description="Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.",
RationaleStatement="The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.",
ImpactStatement="",
RemediationProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```",
AuditProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the permissions are `600` or more restrictive.",
AdditionalInformation="",
References="https://kubernetes.io/docs/admin/kube-apiserver/",
DefaultValue="By default, the `kube-controller-manager.yaml` file has permissions of `640`.",
)
],
)
],
)
CIS_1_5_AWS_NAME = "cis_1.5_aws"
CIS_1_5_AWS = ComplianceBaseModel(
Framework="CIS",
Provider="AWS",
Version="1.5",
Description="The CIS Amazon Web Services Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Amazon Web Services with an emphasis on foundational, testable, and architecture agnostic settings.",
Requirements=[
Compliance_Requirement(
Checks=[],
Id="2.1.3",
Description="Ensure MFA Delete is enabled on S3 buckets",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1. Simple Storage Service (S3)",
Profile="Level 1",
AssessmentStatus="Automated",
Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
ImpactStatement="",
RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.\n\nNote:\n-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.\n-You must use your 'root' account to enable MFA Delete on S3 buckets.\n\n**From Command line:**\n\n1. Run the s3api put-bucket-versioning command\n\n```\naws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa “arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode”\n```",
AuditProcedure='Perform the steps below to confirm MFA delete is configured on an S3 Bucket\n\n**From Console:**\n\n1. Login to the S3 console at `https://console.aws.amazon.com/s3/`\n\n2. Click the `Check` box next to the Bucket name you want to confirm\n\n3. In the window under `Properties`\n\n4. Confirm that Versioning is `Enabled`\n\n5. Confirm that MFA Delete is `Enabled`\n\n**From Command Line:**\n\n1. Run the `get-bucket-versioning`\n```\naws s3api get-bucket-versioning --bucket my-bucket\n```\n\nOutput example:\n```\n<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> \n <Status>Enabled</Status>\n <MfaDelete>Enabled</MfaDelete> \n</VersioningConfiguration>\n```\n\nIf the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.',
AdditionalInformation="",
References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
)
],
)
],
)
NOT_PRESENT_COMPLIANCE_NAME = "not_present_compliance_name"
NOT_PRESENT_COMPLIANCE = ComplianceBaseModel(
Framework="NOT_EXISTENT",
Provider="NOT_EXISTENT",
Version="NOT_EXISTENT",
Description="NOT_EXISTENT",
Requirements=[],
)
+4 -2
View File
@@ -10,6 +10,8 @@ def generate_finding_output(
status_extended: str = "",
severity: str = "high",
muted: bool = False,
account_uid: str = AWS_ACCOUNT_NUMBER,
account_name: str = AWS_ACCOUNT_NUMBER,
region: str = AWS_REGION_EU_WEST_1,
resource_details: str = "",
resource_uid: str = "",
@@ -36,8 +38,8 @@ def generate_finding_output(
return Finding(
auth_method="profile: default",
timestamp=timestamp if timestamp else datetime.now(),
account_uid=AWS_ACCOUNT_NUMBER,
account_name=AWS_ACCOUNT_NUMBER,
account_uid=account_uid,
account_name=account_name,
account_email="",
account_organization_uid="test-organization-id",
account_organization_name="test-organization",
+9 -9
View File
@@ -6,8 +6,8 @@ from colorama import Fore
from prowler.lib.check.compliance_models import (
CIS_Requirement_Attribute,
Compliance_Base_Model,
Compliance_Requirement,
ComplianceBaseModel,
)
from prowler.lib.check.models import Check_Report, load_check_metadata
from prowler.lib.outputs.compliance.compliance import get_check_compliance
@@ -329,7 +329,7 @@ class TestOutputs:
def test_get_check_compliance_aws(self):
bulk_check_metadata = [
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="AWS",
Version="1.4",
@@ -356,7 +356,7 @@ class TestOutputs:
)
],
),
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="AWS",
Version="1.5",
@@ -413,7 +413,7 @@ class TestOutputs:
def test_get_check_compliance_gcp(self):
bulk_check_metadata = [
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="GCP",
Version="2.0",
@@ -440,7 +440,7 @@ class TestOutputs:
)
],
),
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="GCP",
Version="2.1",
@@ -497,7 +497,7 @@ class TestOutputs:
def test_get_check_compliance_azure(self):
bulk_check_metadata = [
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="Azure",
Version="2.0",
@@ -524,7 +524,7 @@ class TestOutputs:
)
],
),
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="Azure",
Version="2.1",
@@ -581,7 +581,7 @@ class TestOutputs:
def test_get_check_compliance_kubernetes(self):
bulk_check_metadata = [
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="Kubernetes",
Version="2.0",
@@ -608,7 +608,7 @@ class TestOutputs:
)
],
),
Compliance_Base_Model(
ComplianceBaseModel(
Framework="CIS",
Provider="Kubernetes",
Version="2.1",
@@ -1,12 +1,14 @@
from kubernetes import client
from mock import MagicMock
from kubernetes import client
from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider
from prowler.providers.kubernetes.models import (
KubernetesIdentityInfo,
KubernetesSession,
)
KUBERNETES_CLUSTER_NAME = "test-cluster"
KUBERNETES_NAMESPACE = "test-namespace"
KUBERNETES_CONFIG = {
"audit_log_maxbackup": 10,
"audit_log_maxsize": 100,