diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index a56ad9efc6..e35dc0eb64 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -612,20 +612,9 @@ class CheckReportM365(Check_Report): class CheckReportIAC(Check_Report): """Contains the IAC Check's finding information using Checkov.""" - metadata: dict - check_id: str - check_name: str - check_result: dict - check_result_status: str - file_path: str - file_line_range: list - guideline: str - resource: str - severity: str - # TODO: comparing with the others, are all the above are necesary? review resource_name: str - resource_id: str - location: str + resource_path: str + resource_line_range: str def __init__(self, metadata: dict = {}, finding: dict = {}) -> None: """ @@ -637,16 +626,6 @@ class CheckReportIAC(Check_Report): """ super().__init__(metadata, finding) - self.check_id = finding.get("check_id", "") - self.check_name = finding.get("check_name", "") - self.check_result = finding.get("check_result", {}) - self.check_result_status = self.check_result.get("result", "UNKNOWN") - self.file_path = finding.get("file_path", "") - self.file_line_range = finding.get("file_line_range", []) - self.guideline = finding.get("guideline", "") - self.resource = finding - self.severity = finding.get("severity", "UNKNOWN") - # TODO: same question above self.resource_name = getattr(finding, "resource", "") self.resource_path = getattr(finding, "file_path", "") self.resource_line_range = getattr(finding, "file_line_range", "") diff --git a/prowler/lib/outputs/compliance/cis/models.py b/prowler/lib/outputs/compliance/cis/models.py index 1a4764c294..433142e0d9 100644 --- a/prowler/lib/outputs/compliance/cis/models.py +++ b/prowler/lib/outputs/compliance/cis/models.py @@ -16,7 +16,7 @@ class AWSCISModel(BaseModel): Requirements_Id: str Requirements_Description: str Requirements_Attributes_Section: str - Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_SubSection: Optional[str] = None Requirements_Attributes_Profile: str Requirements_Attributes_AssessmentStatus: str Requirements_Attributes_Description: str @@ -50,7 +50,7 @@ class AzureCISModel(BaseModel): Requirements_Id: str Requirements_Description: str Requirements_Attributes_Section: str - Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_SubSection: Optional[str] = None Requirements_Attributes_Profile: str Requirements_Attributes_AssessmentStatus: str Requirements_Attributes_Description: str @@ -82,7 +82,7 @@ class M365CISModel(BaseModel): Requirements_Id: str Requirements_Description: str Requirements_Attributes_Section: str - Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_SubSection: Optional[str] = None Requirements_Attributes_Profile: str Requirements_Attributes_AssessmentStatus: str Requirements_Attributes_Description: str @@ -114,7 +114,7 @@ class GCPCISModel(BaseModel): Requirements_Id: str Requirements_Description: str Requirements_Attributes_Section: str - Requirements_Attributes_SubSection: Optional[str] + Requirements_Attributes_SubSection: Optional[str] = None Requirements_Attributes_Profile: str Requirements_Attributes_AssessmentStatus: str Requirements_Attributes_Description: str @@ -145,8 +145,8 @@ class KubernetesCISModel(BaseModel): Requirements_Id: str Requirements_Description: str Requirements_Attributes_Section: str - Requirements_Attributes_SubSection: Optional[str] - Requirements_Attributes_Profile: str + Requirements_Attributes_SubSection: Optional[str] = None + Requirements_Attributes_Profile: Optional[str] = None Requirements_Attributes_AssessmentStatus: str Requirements_Attributes_Description: str Requirements_Attributes_RationaleStatement: str diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index b13a860b66..347a31ecd0 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -288,8 +288,7 @@ class Finding(BaseModel): output_data["account_name"] = "iac" output_data["resource_name"] = check_output.resource["resource"] output_data["resource_uid"] = check_output.resource["resource"] - output_data["region"] = check_output.file_path - output_data["resource_path"] = check_output.resource_path + output_data["region"] = check_output.resource_path output_data["resource_line_range"] = check_output.resource_line_range output_data["framework"] = ( check_output.check_metadata.ServiceName diff --git a/prowler/providers/azure/models.py b/prowler/providers/azure/models.py index cf0cd4be9b..1745e67214 100644 --- a/prowler/providers/azure/models.py +++ b/prowler/providers/azure/models.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import BaseModel from prowler.config.config import output_file_timestamp @@ -15,7 +17,7 @@ class AzureIdentityInfo(BaseModel): class AzureRegionConfig(BaseModel): name: str = "" - authority: str = None + authority: Optional[str] = None base_url: str = "" credential_scopes: list = [] diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 44e7b067c3..e7f4a74c2f 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -247,7 +247,6 @@ class Provider(ABC): provider_class( scan_path=arguments.scan_path, config_path=arguments.config_file, - mutelist_path=arguments.mutelist_file, fixer_config=fixer_config, ) diff --git a/prowler/providers/gcp/models.py b/prowler/providers/gcp/models.py index 4abdd6b0ff..a6d925fd2f 100644 --- a/prowler/providers/gcp/models.py +++ b/prowler/providers/gcp/models.py @@ -14,7 +14,7 @@ class GCPOrganization(BaseModel): id: str name: str # TODO: the name needs to be retrieved from another API - display_name: Optional[str] + display_name: Optional[str] = None class GCPProject(BaseModel): diff --git a/prowler/providers/iac/iac_provider.py b/prowler/providers/iac/iac_provider.py index a8f3d74c80..6c6b9da6ad 100644 --- a/prowler/providers/iac/iac_provider.py +++ b/prowler/providers/iac/iac_provider.py @@ -5,6 +5,10 @@ from typing import List from colorama import Fore, Style +from prowler.config.config import ( + default_config_file_path, + load_and_validate_config_file, +) from prowler.lib.check.models import CheckReportIAC from prowler.lib.logger import logger from prowler.lib.utils.utils import print_boxes @@ -22,8 +26,6 @@ class IacProvider(Provider): config_path: str = None, config_content: dict = None, fixer_config: dict = {}, - mutelist_path: str = None, - mutelist_content: dict = None, ): logger.info("Instantiating IAC Provider...") @@ -33,8 +35,18 @@ class IacProvider(Provider): self._session = None self._identity = "prowler" - self._audit_config = config_content if config_content else {} + # Audit Config + if config_content: + self._audit_config = config_content + else: + if not config_path: + config_path = default_config_file_path + self._audit_config = load_and_validate_config_file(self._type, config_path) + + # Fixer Config self._fixer_config = fixer_config + + # Mutelist (not needed for IAC since Checkov has its own mutelist logic) self._mutelist = None self.audit_metadata = Audit_Metadata( @@ -86,22 +98,17 @@ class IacProvider(Provider): Returns: CheckReportIAC: The processed check report """ - # Get severity and ensure it's a valid string - severity = finding.get("severity", "low") - if severity is None: - severity = "low" - severity = str(severity).lower() - - # Create a basic metadata structure for the check metadata_dict = { "Provider": "iac", "CheckID": check.get("check_id", ""), "CheckTitle": check.get("check_name", ""), "CheckType": ["Infrastructure as Code"], - "ServiceName": "iac", + "ServiceName": finding["check_type"], "SubServiceName": "", "ResourceIdTemplate": "", - "Severity": severity, + "Severity": ( + check.get("severity", "low").lower() if check.get("severity") else "low" + ), "ResourceType": "iac", "Description": check.get("check_name", ""), "Risk": "", @@ -126,7 +133,6 @@ class IacProvider(Provider): "DependsOn": [], "RelatedTo": [], "Notes": "", - "GCPProject": check.get("project_id", ""), } # Convert metadata dict to JSON string @@ -134,6 +140,10 @@ class IacProvider(Provider): report = CheckReportIAC(metadata=metadata, finding=check) report.status = status + report.resource_tags = check.get("entity_tags", {}) + report.status_extended = check.get("check_name", "") + if status == "MUTED": + report.muted = True return report def run(self) -> List[CheckReportIAC]: @@ -161,7 +171,11 @@ class IacProvider(Provider): reports = [] - # Process all findings + # If only one framework has findings, the output is a dict, otherwise it's a list of dicts + if isinstance(output, dict): + output = [output] + + # Process all frameworks findings for finding in output: results = finding.get("results", {}) @@ -177,6 +191,12 @@ class IacProvider(Provider): report = self._process_check(finding, passed_check, "PASS") reports.append(report) + # Process skipped checks (muted) + skipped_checks = results.get("skipped_checks", []) + for skipped_check in skipped_checks: + report = self._process_check(finding, skipped_check, "MUTED") + reports.append(report) + return reports except Exception as error: diff --git a/prowler/providers/kubernetes/services/core/core_service.py b/prowler/providers/kubernetes/services/core/core_service.py index ec6fb48ca8..98138d0d79 100644 --- a/prowler/providers/kubernetes/services/core/core_service.py +++ b/prowler/providers/kubernetes/services/core/core_service.py @@ -171,7 +171,7 @@ class Pod(BaseModel): host_ip: Optional[str] host_pid: Optional[str] host_ipc: Optional[str] - host_network: Optional[str] + host_network: Optional[bool] security_context: Optional[dict] containers: Optional[dict]