feat(resource metadata): add resource metadata to JSON OCSF (#6592)

Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
This commit is contained in:
Sergio Garcia
2025-01-23 05:21:30 -05:00
committed by Pepe Fagoaga
parent b1de41619b
commit 11d9cdf24e
894 changed files with 1773 additions and 2586 deletions
+40 -65
View File
@@ -3,7 +3,7 @@ import os
import re
import sys
from abc import ABC, abstractmethod
from dataclasses import dataclass
from dataclasses import asdict, dataclass, is_dataclass
from enum import Enum
from typing import Any, Dict, Set
@@ -405,36 +405,34 @@ class Check_Report:
status: str
status_extended: str
check_metadata: CheckMetadata
resource_metadata: dict
resource: dict
resource_details: str
resource_tags: list
muted: bool
def __init__(self, metadata: Dict, resource: Any = None) -> None:
def __init__(self, metadata: Dict, resource: Any) -> None:
"""Initialize the Check's finding information.
Args:
metadata: The metadata of the check.
resource: Basic information about the resource. Defaults to None.
Only accepted dict, list, BaseModels (dict attribute), custom models (with to_dict attribute) or objects with __dict__.
Only accepted dict, list, BaseModels (dict attribute), custom models (with to_dict attribute) and dataclasses.
"""
self.status = ""
self.check_metadata = CheckMetadata.parse_raw(metadata)
if isinstance(resource, dict):
self.resource_metadata = resource
elif isinstance(resource, list):
self.resource_metadata = dict(enumerate(resource))
self.resource = resource
elif hasattr(resource, "dict"):
self.resource_metadata = resource.dict()
self.resource = resource.dict()
elif hasattr(resource, "to_dict"):
self.resource_metadata = resource.to_dict()
elif hasattr(resource, "__dict__"):
self.resource_metadata = resource.__dict__
self.resource = resource.to_dict()
elif is_dataclass(resource):
self.resource = asdict(resource)
else:
logger.error(
f"Resource metadata {type(resource)} could not be converted to dict"
f"Resource metadata {type(resource)} in {self.check_metadata.CheckID} could not be converted to dict"
)
self.resource_metadata = {}
self.resource = {}
self.status_extended = ""
self.resource_details = ""
self.resource_tags = getattr(resource, "tags", []) if resource else []
@@ -449,20 +447,13 @@ class Check_Report_AWS(Check_Report):
resource_arn: str
region: str
def __init__(self, metadata, resource_metadata=None):
super().__init__(metadata, resource_metadata)
if resource_metadata:
self.resource_id = (
getattr(resource_metadata, "id", None)
or getattr(resource_metadata, "name", None)
or ""
)
self.resource_arn = getattr(resource_metadata, "arn", "")
self.region = getattr(resource_metadata, "region", "")
else:
self.resource_id = ""
self.resource_arn = ""
self.region = ""
def __init__(self, metadata: Dict, resource: Any) -> None:
super().__init__(metadata, resource)
self.resource_id = (
getattr(resource, "id", None) or getattr(resource, "name", None) or ""
)
self.resource_arn = getattr(resource, "arn", "")
self.region = getattr(resource, "region", "")
@dataclass
@@ -474,34 +465,20 @@ class Check_Report_Azure(Check_Report):
subscription: str
location: str
def __init__(self, metadata: Dict, resource_metadata: Any = None) -> None:
def __init__(self, metadata: Dict, resource: Any) -> None:
"""Initialize the Azure Check's finding information.
Args:
metadata: The metadata of the check.
resource_metadata: Basic information about the resource. Defaults to None.
resource: Basic information about the resource. Defaults to None.
"""
super().__init__(metadata, resource_metadata)
self.resource_name = (
resource_metadata.name
if hasattr(resource_metadata, "name")
else (
resource_metadata.resource_name
if hasattr(resource_metadata, "resource_name")
else ""
)
)
self.resource_id = (
resource_metadata.id
if hasattr(resource_metadata, "id")
else (
resource_metadata.resource_id
if hasattr(resource_metadata, "resource_id")
else ""
)
super().__init__(metadata, resource)
self.resource_name = getattr(
resource, "name", getattr(resource, "resource_name", "")
)
self.resource_id = getattr(resource, "id", getattr(resource, "resource_id", ""))
self.subscription = ""
self.location = getattr(resource_metadata, "location", "global")
self.location = getattr(resource, "location", "global")
@dataclass
@@ -515,26 +492,26 @@ class Check_Report_GCP(Check_Report):
def __init__(
self,
metadata,
resource_metadata,
metadata: Dict,
resource: Any,
location=None,
resource_name=None,
resource_id=None,
project_id=None,
):
super().__init__(metadata, resource_metadata)
) -> None:
super().__init__(metadata, resource)
self.resource_id = (
resource_id
or getattr(resource_metadata, "id", None)
or getattr(resource_metadata, "name", None)
or getattr(resource, "id", None)
or getattr(resource, "name", None)
or ""
)
self.resource_name = resource_name or getattr(resource_metadata, "name", "")
self.project_id = project_id or getattr(resource_metadata, "project_id", "")
self.resource_name = resource_name or getattr(resource, "name", "")
self.project_id = project_id or getattr(resource, "project_id", "")
self.location = (
location
or getattr(resource_metadata, "location", "")
or getattr(resource_metadata, "region", "")
or getattr(resource, "location", "")
or getattr(resource, "region", "")
)
@@ -547,15 +524,13 @@ class Check_Report_Kubernetes(Check_Report):
resource_id: str
namespace: str
def __init__(self, metadata, resource_metadata):
super().__init__(metadata, resource_metadata)
def __init__(self, metadata: Dict, resource: Any) -> None:
super().__init__(metadata, resource)
self.resource_id = (
getattr(resource_metadata, "uid", None)
or getattr(resource_metadata, "name", None)
or ""
getattr(resource, "uid", None) or getattr(resource, "name", None) or ""
)
self.resource_name = getattr(resource_metadata, "name", "")
self.namespace = getattr(resource_metadata, "namespace", "cluster-wide")
self.resource_name = getattr(resource, "name", "")
self.namespace = getattr(resource, "namespace", "cluster-wide")
if not self.namespace:
self.namespace = "cluster-wide"
+1 -1
View File
@@ -14,7 +14,7 @@ def fill_common_finding_data(finding: dict, unix_timestamp: bool) -> dict:
"status_extended": finding.status_extended,
"muted": finding.muted,
"resource_details": finding.resource_details,
# "resource_metadata": finding.resource_metadata, TODO: add resource_metadata to the finding
"resource": finding.resource,
"resource_tags": unroll_tags(finding.resource_tags),
}
return finding_data
+2 -1
View File
@@ -35,7 +35,7 @@ class Finding(BaseModel):
status_extended: str
muted: bool = False
resource_uid: str
# resource_metadata: dict = Field(default_factory=dict) TODO: add resource_metadata to the finding
resource_metadata: dict = Field(default_factory=dict)
resource_name: str
resource_details: str
resource_tags: dict = Field(default_factory=dict)
@@ -121,6 +121,7 @@ class Finding(BaseModel):
)
try:
output_data["provider"] = provider.type
output_data["resource_metadata"] = check_output.resource
if provider.type == "aws":
output_data["account_uid"] = get_nested_attribute(
+11 -6
View File
@@ -122,7 +122,7 @@ class OCSF(Output):
region=finding.region,
data={
"details": finding.resource_details,
# "metadata": finding.resource_metadata, TODO: add the resource_metadata to the finding
"metadata": finding.resource_metadata,
},
)
]
@@ -136,7 +136,7 @@ class OCSF(Output):
type=finding.metadata.ResourceType,
data={
"details": finding.resource_details,
# "metadata": finding.resource_metadata, TODO: add the resource_metadata to the finding
"metadata": finding.resource_metadata,
},
namespace=finding.region.replace("namespace: ", ""),
)
@@ -202,10 +202,15 @@ class OCSF(Output):
):
self._file_descriptor.write("[")
for finding in self._data:
self._file_descriptor.write(
finding.json(exclude_none=True, indent=4)
)
self._file_descriptor.write(",")
try:
self._file_descriptor.write(
finding.json(exclude_none=True, indent=4)
)
self._file_descriptor.write(",")
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
if self._file_descriptor.tell() > 0:
if self._file_descriptor.tell() != 1:
self._file_descriptor.seek(
@@ -8,9 +8,7 @@ class accessanalyzer_enabled(Check):
def execute(self):
findings = []
for analyzer in accessanalyzer_client.analyzers:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=analyzer
)
report = Check_Report_AWS(metadata=self.metadata(), resource=analyzer)
if analyzer.status == "ACTIVE":
report.status = "PASS"
report.status_extended = (
@@ -8,9 +8,7 @@ class accessanalyzer_enabled_without_findings(Check):
def execute(self):
findings = []
for analyzer in accessanalyzer_client.analyzers:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=analyzer
)
report = Check_Report_AWS(metadata=self.metadata(), resource=analyzer)
if analyzer.status == "ACTIVE":
report.status = "PASS"
report.status_extended = f"IAM Access Analyzer {analyzer.name} does not have active findings."
@@ -7,7 +7,7 @@ from prowler.providers.aws.services.account.account_client import account_client
class account_maintain_current_contact_details(Check):
def execute(self):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=account_client.contact_base
metadata=self.metadata(), resource=account_client.contact_base
)
report.region = account_client.region
report.resource_id = account_client.audited_account
@@ -9,7 +9,7 @@ class account_maintain_different_contact_details_to_security_billing_and_operati
findings = []
if account_client.contact_base:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=account_client.contact_base
metadata=self.metadata(), resource=account_client.contact_base
)
report.resource_id = account_client.audited_account
report.resource_arn = account_client.audited_account_arn
@@ -7,7 +7,7 @@ from prowler.providers.aws.services.account.account_client import account_client
class account_security_contact_information_is_registered(Check):
def execute(self):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=account_client.contact_base
metadata=self.metadata(), resource=account_client.contact_base
)
report.region = account_client.region
report.resource_id = account_client.audited_account
@@ -7,7 +7,7 @@ from prowler.providers.aws.services.account.account_client import account_client
class account_security_questions_are_registered_in_the_aws_account(Check):
def execute(self):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=account_client.contacts_security
metadata=self.metadata(), resource=account_client.contacts_security
)
report.region = account_client.region
report.resource_id = account_client.audited_account
@@ -8,7 +8,7 @@ class acm_certificates_expiration_check(Check):
for certificate in acm_client.certificates.values():
if certificate.in_use or acm_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=certificate
metadata=self.metadata(), resource=certificate
)
if certificate.expiration_days > acm_client.audit_config.get(
"days_to_expire_threshold", 7
@@ -8,7 +8,7 @@ class acm_certificates_transparency_logs_enabled(Check):
for certificate in acm_client.certificates.values():
if certificate.in_use or acm_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=certificate
metadata=self.metadata(), resource=certificate
)
if certificate.type == "IMPORTED":
report.status = "PASS"
@@ -8,7 +8,7 @@ class acm_certificates_with_secure_key_algorithms(Check):
for certificate in acm_client.certificates.values():
if certificate.in_use or acm_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=certificate
metadata=self.metadata(), resource=certificate
)
report.status = "PASS"
@@ -8,9 +8,7 @@ class apigateway_restapi_authorizers_enabled(Check):
def execute(self):
findings = []
for rest_api in apigateway_client.rest_apis:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=rest_api
)
report = Check_Report_AWS(metadata=self.metadata(), resource=rest_api)
report.resource_id = rest_api.name
# it there are not authorizers at api level and resources without methods (default case) ->
@@ -10,9 +10,7 @@ class apigateway_restapi_cache_encrypted(Check):
for rest_api in apigateway_client.rest_apis:
for stage in rest_api.stages:
if stage.cache_enabled:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stage
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stage)
report.region = rest_api.region
report.resource_id = rest_api.name
report.status = "PASS"
@@ -9,9 +9,7 @@ class apigateway_restapi_client_certificate_enabled(Check):
findings = []
for rest_api in apigateway_client.rest_apis:
for stage in rest_api.stages:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stage
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stage)
report.resource_id = rest_api.name
report.region = rest_api.region
if stage.client_certificate:
@@ -9,9 +9,7 @@ class apigateway_restapi_logging_enabled(Check):
findings = []
for rest_api in apigateway_client.rest_apis:
for stage in rest_api.stages:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stage
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stage)
report.resource_id = rest_api.name
report.region = rest_api.region
if stage.logging:
@@ -8,9 +8,7 @@ class apigateway_restapi_public(Check):
def execute(self):
findings = []
for rest_api in apigateway_client.rest_apis:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=rest_api
)
report = Check_Report_AWS(metadata=self.metadata(), resource=rest_api)
report.resource_id = rest_api.name
if rest_api.public_endpoint:
@@ -9,9 +9,7 @@ class apigateway_restapi_public_with_authorizer(Check):
findings = []
for rest_api in apigateway_client.rest_apis:
if rest_api.public_endpoint:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=rest_api
)
report = Check_Report_AWS(metadata=self.metadata(), resource=rest_api)
report.resource_id = rest_api.name
report.status = "PASS"
@@ -9,9 +9,7 @@ class apigateway_restapi_tracing_enabled(Check):
findings = []
for rest_api in apigateway_client.rest_apis:
for stage in rest_api.stages:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stage
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stage)
report.region = rest_api.region
report.resource_id = rest_api.name
report.status = "FAIL"
@@ -9,9 +9,7 @@ class apigateway_restapi_waf_acl_attached(Check):
findings = []
for rest_api in apigateway_client.rest_apis:
for stage in rest_api.stages:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stage
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stage)
report.resource_id = rest_api.name
report.region = rest_api.region
if stage.waf:
@@ -8,7 +8,7 @@ class apigatewayv2_api_access_logging_enabled(Check):
def execute(self):
findings = []
for api in apigatewayv2_client.apis:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=api)
report = Check_Report_AWS(metadata=self.metadata(), resource=api)
for stage in api.stages:
if stage.logging:
report.status = "PASS"
@@ -8,7 +8,7 @@ class apigatewayv2_api_authorizers_enabled(Check):
def execute(self):
findings = []
for api in apigatewayv2_client.apis:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=api)
report = Check_Report_AWS(metadata=self.metadata(), resource=api)
report.resource_id = api.name
report.status = "FAIL"
report.status_extended = f"API Gateway V2 {api.name} ID {api.id} does not have an authorizer configured."
@@ -10,7 +10,7 @@ class appstream_fleet_default_internet_access_disabled(Check):
"""Execute the appstream_fleet_default_internet_access_disabled check"""
findings = []
for fleet in appstream_client.fleets:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=fleet)
report = Check_Report_AWS(metadata=self.metadata(), resource=fleet)
if fleet.enable_default_internet_access:
report.status = "FAIL"
@@ -15,7 +15,7 @@ class appstream_fleet_maximum_session_duration(Check):
findings = []
for fleet in appstream_client.fleets:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=fleet)
report = Check_Report_AWS(metadata=self.metadata(), resource=fleet)
if fleet.max_user_duration_in_seconds < max_session_duration_seconds:
report.status = "PASS"
@@ -15,7 +15,7 @@ class appstream_fleet_session_disconnect_timeout(Check):
findings = []
for fleet in appstream_client.fleets:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=fleet)
report = Check_Report_AWS(metadata=self.metadata(), resource=fleet)
if fleet.disconnect_timeout_in_seconds <= max_disconnect_timeout_in_seconds:
report.status = "PASS"
@@ -15,7 +15,7 @@ class appstream_fleet_session_idle_disconnect_timeout(Check):
findings = []
for fleet in appstream_client.fleets:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=fleet)
report = Check_Report_AWS(metadata=self.metadata(), resource=fleet)
if (
fleet.idle_disconnect_timeout_in_seconds
@@ -7,7 +7,7 @@ class appsync_field_level_logging_enabled(Check):
findings = []
# Check only GraphQL APIs because boto3 does not have a method to get other types of AppSync APIs (list_apis is not working)
for api in appsync_client.graphql_apis.values():
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=api)
report = Check_Report_AWS(metadata=self.metadata(), resource=api)
report.status = "PASS"
report.status_extended = (
f"AppSync API {api.name} has field log level enabled."
@@ -7,9 +7,7 @@ class appsync_graphql_api_no_api_key_authentication(Check):
findings = []
for api in appsync_client.graphql_apis.values():
if api.type == "GRAPHQL":
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=api
)
report = Check_Report_AWS(metadata=self.metadata(), resource=api)
report.status = "PASS"
report.status_extended = f"AppSync GraphQL API {api.name} is not using an API KEY for authentication."
if api.authentication_type == "API_KEY":
@@ -13,9 +13,7 @@ class athena_workgroup_encryption(Check):
if (
workgroup.state == "ENABLED" and workgroup.queries
) or athena_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=workgroup
)
report = Check_Report_AWS(metadata=self.metadata(), resource=workgroup)
if workgroup.encryption_configuration.encrypted:
report.status = "PASS"
@@ -13,9 +13,7 @@ class athena_workgroup_enforce_configuration(Check):
if (
workgroup.state == "ENABLED" and workgroup.queries
) or athena_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=workgroup
)
report = Check_Report_AWS(metadata=self.metadata(), resource=workgroup)
if workgroup.enforce_workgroup_configuration:
report.status = "PASS"
@@ -21,9 +21,7 @@ class athena_workgroup_logging_enabled(Check):
if (
workgroup.state == "ENABLED" and workgroup.queries
) or athena_client.provider.scan_unused_services:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=workgroup
)
report = Check_Report_AWS(metadata=self.metadata(), resource=workgroup)
report.status = "PASS"
report.status_extended = (
f"Athena WorkGroup {workgroup.name} has CloudWatch logging enabled."
@@ -20,9 +20,7 @@ class autoscaling_find_secrets_ec2_launch_configuration(Check):
configuration_arn,
configuration,
) in autoscaling_client.launch_configurations.items():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=configuration
)
report = Check_Report_AWS(metadata=self.metadata(), resource=configuration)
if configuration.user_data:
user_data = b64decode(configuration.user_data)
@@ -9,9 +9,7 @@ class autoscaling_group_capacity_rebalance_enabled(Check):
findings = []
for group in autoscaling_client.groups:
if group.load_balancers and group.target_groups:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "FAIL"
report.status_extended = f"Autoscaling group {group.name} does not have capacity rebalance enabled."
@@ -9,9 +9,7 @@ class autoscaling_group_elb_health_check_enabled(Check):
findings = []
for group in autoscaling_client.groups:
if group.load_balancers and group.target_groups:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "FAIL"
report.status_extended = f"Autoscaling group {group.name} is associated with a load balancer but does not have ELB health checks enabled, instead it has {group.health_check_type} health checks."
@@ -10,9 +10,7 @@ class autoscaling_group_launch_configuration_no_public_ip(Check):
for group in autoscaling_client.groups:
for lc in autoscaling_client.launch_configurations.values():
if lc.name == group.launch_configuration_name:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "PASS"
report.status_extended = f"Autoscaling group {group.name} does not have an associated launch configuration assigning a public IP address."
@@ -12,9 +12,7 @@ class autoscaling_group_launch_configuration_requires_imdsv2(Check):
launch_configuration
) in autoscaling_client.launch_configurations.values():
if launch_configuration.name == group.launch_configuration_name:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "FAIL"
report.status_extended = f"Autoscaling group {group.name} has IMDSv2 disabled or not required."
@@ -8,7 +8,7 @@ class autoscaling_group_multiple_az(Check):
def execute(self):
findings = []
for group in autoscaling_client.groups:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=group)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "FAIL"
report.status_extended = (
@@ -8,7 +8,7 @@ class autoscaling_group_multiple_instance_types(Check):
def execute(self):
findings = []
for group in autoscaling_client.groups:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=group)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "FAIL"
report.status_extended = f"Autoscaling group {group.name} does not have multiple instance types in multiple Availability Zones."
@@ -8,7 +8,7 @@ class autoscaling_group_using_ec2_launch_template(Check):
def execute(self):
findings = []
for group in autoscaling_client.groups:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=group)
report = Check_Report_AWS(metadata=self.metadata(), resource=group)
report.status = "PASS"
report.status_extended = (
@@ -8,9 +8,7 @@ class awslambda_function_inside_vpc(Check):
def execute(self) -> List[Check_Report_AWS]:
findings = []
for function_arn, function in awslambda_client.functions.items():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "PASS"
report.status_extended = (
@@ -9,9 +9,7 @@ class awslambda_function_invoke_api_operations_cloudtrail_logging_enabled(Check)
def execute(self):
findings = []
for function in awslambda_client.functions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "FAIL"
report.status_extended = (
@@ -16,7 +16,7 @@ class awslambda_function_no_secrets_in_code(Check):
for function, function_code in awslambda_client._get_function_code():
if function_code:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
metadata=self.metadata(), resource=function
)
report.status = "PASS"
@@ -13,9 +13,7 @@ class awslambda_function_no_secrets_in_variables(Check):
"secrets_ignore_patterns", []
)
for function in awslambda_client.functions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "PASS"
report.status_extended = (
@@ -7,9 +7,7 @@ class awslambda_function_not_publicly_accessible(Check):
def execute(self):
findings = []
for function in awslambda_client.functions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "PASS"
report.status_extended = f"Lambda function {function.name} has a policy resource-based policy not public."
@@ -6,9 +6,7 @@ class awslambda_function_url_cors_policy(Check):
def execute(self):
findings = []
for function in awslambda_client.functions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
if function.url_config:
if "*" in function.url_config.cors_config.allow_origins:
@@ -7,9 +7,7 @@ class awslambda_function_url_public(Check):
def execute(self):
findings = []
for function in awslambda_client.functions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
if function.url_config:
if function.url_config.auth_type == AuthType.AWS_IAM:
@@ -33,9 +33,7 @@ class awslambda_function_using_supported_runtimes(Check):
findings = []
for function in awslambda_client.functions.values():
if function.runtime:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
if function.runtime in awslambda_client.audit_config.get(
"obsolete_lambda_runtimes", default_obsolete_lambda_runtimes
@@ -16,9 +16,7 @@ class awslambda_function_vpc_multi_az(Check):
awslambda_function_inside_vpc.__name__,
function_arn,
):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=function
)
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "FAIL"
report.status_extended = (
@@ -8,14 +8,14 @@ class backup_plans_exist(Check):
if backup_client.backup_plans:
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=backup_client.backup_plans[0],
resource=backup_client.backup_plans[0],
)
report.status = "PASS"
report.status_extended = f"At least one Backup Plan exists: {backup_client.backup_plans[0].name}."
report.resource_id = backup_client.backup_plans[0].name
findings.append(report)
elif backup_client.backup_vaults:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata={})
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.region = backup_client.region
report.status = "FAIL"
report.status_extended = "No Backup Plan exist."
@@ -6,9 +6,7 @@ class backup_recovery_point_encrypted(Check):
def execute(self):
findings = []
for recovery_point in backup_client.recovery_points:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=recovery_point
)
report = Check_Report_AWS(metadata=self.metadata(), resource=recovery_point)
report.region = recovery_point.backup_vault_region
report.status = "FAIL"
report.status_extended = f"Backup Recovery Point {recovery_point.id} for Backup Vault {recovery_point.backup_vault_name} is not encrypted at rest."
@@ -9,7 +9,7 @@ class backup_reportplans_exist(Check):
if backup_client.backup_plans:
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=backup_client.backup_plans[0],
resource=backup_client.backup_plans[0],
)
report.resource_arn = backup_client.report_plan_arn_template
report.resource_id = backup_client.audited_account
@@ -19,7 +19,7 @@ class backup_reportplans_exist(Check):
if backup_client.backup_report_plans:
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=backup_client.backup_report_plans[0],
resource=backup_client.backup_report_plans[0],
)
report.status = "PASS"
report.status_extended = f"At least one backup report plan exists: {backup_client.backup_report_plans[0].name}."
@@ -8,7 +8,7 @@ class backup_vaults_encrypted(Check):
if backup_client.backup_vaults:
for backup_vault in backup_client.backup_vaults:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=backup_vault
metadata=self.metadata(), resource=backup_vault
)
report.status = "FAIL"
report.status_extended = (
@@ -6,9 +6,7 @@ class backup_vaults_exist(Check):
def execute(self):
findings = []
if backup_client.backup_vaults is not None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=backup_client.backup_vaults
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.resource_arn = backup_client.backup_vault_arn_template
report.resource_id = backup_client.audited_account
report.region = backup_client.region
@@ -18,7 +16,7 @@ class backup_vaults_exist(Check):
if backup_client.backup_vaults:
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=backup_client.backup_vaults[0],
resource=backup_client.backup_vaults[0],
)
report.status = "PASS"
report.status_extended = f"At least one backup vault exists: {backup_client.backup_vaults[0].name}."
@@ -8,7 +8,7 @@ class bedrock_agent_guardrail_enabled(Check):
def execute(self):
findings = []
for agent in bedrock_agent_client.agents.values():
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=agent)
report = Check_Report_AWS(metadata=self.metadata(), resource=agent)
report.status = "FAIL"
report.status_extended = f"Bedrock Agent {agent.name} is not using any guardrail to protect agent sessions."
if agent.guardrail_id:
@@ -6,9 +6,7 @@ class bedrock_guardrail_prompt_attack_filter_enabled(Check):
def execute(self):
findings = []
for guardrail in bedrock_client.guardrails.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=guardrail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=guardrail)
report.status = "PASS"
report.status_extended = f"Bedrock Guardrail {guardrail.name} is configured to detect and block prompt attacks with a HIGH strength."
if not guardrail.prompt_attack_filter_strength:
@@ -6,9 +6,7 @@ class bedrock_guardrail_sensitive_information_filter_enabled(Check):
def execute(self):
findings = []
for guardrail in bedrock_client.guardrails.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=guardrail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=guardrail)
report.status = "PASS"
report.status_extended = f"Bedrock Guardrail {guardrail.name} is blocking or masking sensitive information."
if not guardrail.sensitive_information_filter:
@@ -6,9 +6,7 @@ class bedrock_model_invocation_logging_enabled(Check):
def execute(self):
findings = []
for region, logging in bedrock_client.logging_configurations.items():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logging
)
report = Check_Report_AWS(metadata=self.metadata(), resource=logging)
report.region = region
report.resource_id = "model-invocation-logging"
report.resource_arn = (
@@ -11,9 +11,7 @@ class bedrock_model_invocation_logs_encryption_enabled(Check):
if logging.enabled:
s3_encryption = True
cloudwatch_encryption = True
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logging
)
report = Check_Report_AWS(metadata=self.metadata(), resource=logging)
report.region = region
report.resource_id = "model-invocation-logging"
report.resource_arn = (
@@ -23,9 +23,7 @@ class cloudformation_stack_cdktoolkit_bootstrap_version(Check):
bootstrap_version = int(output.split(":")[1])
break
if bootstrap_version:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stack
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stack)
report.status = "PASS"
report.status_extended = f"CloudFormation Stack CDKToolkit has a Bootstrap version {bootstrap_version}, which meets the recommended version."
if bootstrap_version < recommended_cdk_bootstrap_version:
@@ -15,7 +15,7 @@ class cloudformation_stack_outputs_find_secrets(Check):
"secrets_ignore_patterns", []
)
for stack in cloudformation_client.stacks:
report = Check_Report_AWS(metadata=self.metadata(), resource_metadata=stack)
report = Check_Report_AWS(metadata=self.metadata(), resource=stack)
report.status = "PASS"
report.status_extended = (
f"No secrets found in CloudFormation Stack {stack.name} Outputs."
@@ -12,9 +12,7 @@ class cloudformation_stacks_termination_protection_enabled(Check):
findings = []
for stack in cloudformation_client.stacks:
if not stack.is_nested_stack:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=stack
)
report = Check_Report_AWS(metadata=self.metadata(), resource=stack)
if stack.enable_termination_protection:
report.status = "PASS"
@@ -8,9 +8,7 @@ class cloudfront_distributions_custom_ssl_certificate(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} is using a custom SSL/TLS certificate."
@@ -8,9 +8,7 @@ class cloudfront_distributions_default_root_object(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if distribution.default_root_object:
report.status = "PASS"
@@ -8,9 +8,7 @@ class cloudfront_distributions_field_level_encryption_enabled(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if (
distribution.default_cache_config
and distribution.default_cache_config.field_level_encryption_id
@@ -11,9 +11,7 @@ class cloudfront_distributions_geo_restrictions_enabled(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if distribution.geo_restriction_type == GeoRestrictionType.none:
report.status = "FAIL"
@@ -11,9 +11,7 @@ class cloudfront_distributions_https_enabled(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if (
distribution.default_cache_config
@@ -13,7 +13,7 @@ class cloudfront_distributions_https_sni_enabled(Check):
for distribution in cloudfront_client.distributions.values():
if distribution.certificate:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
metadata=self.metadata(), resource=distribution
)
if distribution.ssl_support_method == SSLSupportMethod.sni_only:
@@ -8,9 +8,7 @@ class cloudfront_distributions_logging_enabled(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if distribution.logging_enabled or (
distribution.default_cache_config
and distribution.default_cache_config.realtime_log_config_arn
@@ -8,9 +8,7 @@ class cloudfront_distributions_multiple_origin_failover_configured(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
report.status = "FAIL"
report.status_extended = f"CloudFront Distribution {distribution.id} does not have an origin group configured with at least 2 origins."
@@ -8,9 +8,7 @@ class cloudfront_distributions_origin_traffic_encrypted(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} does encrypt traffic to custom origins."
unencrypted_origins = []
@@ -8,9 +8,7 @@ class cloudfront_distributions_s3_origin_access_control(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if any(origin.s3_origin_config for origin in distribution.origins):
s3_buckets_with_no_oac = []
@@ -9,9 +9,7 @@ class cloudfront_distributions_s3_origin_non_existent_bucket(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} does not have non-existent S3 buckets as origins."
non_existent_buckets = []
@@ -11,9 +11,7 @@ class cloudfront_distributions_using_deprecated_ssl_protocols(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} is not using a deprecated SSL protocol."
@@ -8,9 +8,7 @@ class cloudfront_distributions_using_waf(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=distribution
)
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if distribution.web_acl_id:
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} is using AWS WAF web ACL {distribution.web_acl_id}."
@@ -13,9 +13,7 @@ class cloudtrail_bucket_requires_mfa_delete(Check):
if trail.is_logging:
trail_bucket_is_in_account = False
trail_bucket = trail.s3_bucket
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "FAIL"
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) does not have MFA delete enabled."
@@ -14,9 +14,7 @@ class cloudtrail_cloudwatch_logging_enabled(Check):
if cloudtrail_client.trails is not None:
for trail in cloudtrail_client.trails.values():
if trail.name:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "PASS"
if trail.is_multiregion:
@@ -10,9 +10,7 @@ class cloudtrail_insights_exist(Check):
if cloudtrail_client.trails is not None:
for trail in cloudtrail_client.trails.values():
if trail.is_logging:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "FAIL"
report.status_extended = f"Trail {trail.name} does not have insight selectors and it is logging."
@@ -10,9 +10,7 @@ class cloudtrail_kms_encryption_enabled(Check):
if cloudtrail_client.trails is not None:
for trail in cloudtrail_client.trails.values():
if trail.name:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "FAIL"
if trail.is_multiregion:
@@ -10,9 +10,7 @@ class cloudtrail_log_file_validation_enabled(Check):
if cloudtrail_client.trails is not None:
for trail in cloudtrail_client.trails.values():
if trail.name:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "FAIL"
if trail.is_multiregion:
@@ -13,9 +13,7 @@ class cloudtrail_logs_s3_bucket_access_logging_enabled(Check):
if trail.name:
trail_bucket_is_in_account = False
trail_bucket = trail.s3_bucket
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "FAIL"
if trail.is_multiregion:
@@ -13,9 +13,7 @@ class cloudtrail_logs_s3_bucket_is_not_publicly_accessible(Check):
if trail.name:
trail_bucket_is_in_account = False
trail_bucket = trail.s3_bucket
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
)
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "PASS"
if trail.is_multiregion:
@@ -12,7 +12,7 @@ class cloudtrail_multi_region_enabled(Check):
for trail in cloudtrail_client.trails.values():
if trail.region == region or trail.is_multiregion:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
metadata=self.metadata(), resource=trail
)
report.region = region
if trail.is_logging:
@@ -10,7 +10,7 @@ class cloudtrail_multi_region_enabled_logging_management_events(Check):
if cloudtrail_client.trails is not None:
for region in cloudtrail_client.regional_clients.keys():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.status = "FAIL"
report.status_extended = "No CloudTrail trails enabled and logging management events were found."
@@ -48,7 +48,7 @@ class cloudtrail_multi_region_enabled_logging_management_events(Check):
trail_is_logging_management_events = True
if trail_is_logging_management_events:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
metadata=self.metadata(), resource=trail
)
report.region = region
report.status = "PASS"
@@ -29,7 +29,7 @@ class cloudtrail_s3_dataevents_read_enabled(Check):
):
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=trail,
resource=trail,
)
report.region = trail.home_region
report.status = "PASS"
@@ -45,7 +45,7 @@ class cloudtrail_s3_dataevents_read_enabled(Check):
and field_selector["Equals"][0] == "AWS::S3::Object"
):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
metadata=self.metadata(), resource=trail
)
report.region = trail.home_region
report.status = "PASS"
@@ -55,7 +55,7 @@ class cloudtrail_s3_dataevents_read_enabled(Check):
s3_client.buckets or cloudtrail_client.provider.scan_unused_services
):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_arn = cloudtrail_client.trail_arn_template
@@ -29,7 +29,7 @@ class cloudtrail_s3_dataevents_write_enabled(Check):
):
report = Check_Report_AWS(
metadata=self.metadata(),
resource_metadata=trail,
resource=trail,
)
report.region = trail.home_region
report.status = "PASS"
@@ -45,7 +45,7 @@ class cloudtrail_s3_dataevents_write_enabled(Check):
and field_selector["Equals"][0] == "AWS::S3::Object"
):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=trail
metadata=self.metadata(), resource=trail
)
report.region = trail.home_region
report.status = "PASS"
@@ -55,7 +55,7 @@ class cloudtrail_s3_dataevents_write_enabled(Check):
s3_client.buckets or cloudtrail_client.provider.scan_unused_services
):
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_arn = cloudtrail_client.trail_arn_template
@@ -160,7 +160,7 @@ class cloudtrail_threat_detection_enumeration(Check):
if len(actions) / len(enumeration_actions) > threshold:
found_potential_enumeration = True
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = aws_identity_arn.split("/")[-1]
@@ -170,7 +170,7 @@ class cloudtrail_threat_detection_enumeration(Check):
findings.append(report)
if not found_potential_enumeration:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = cloudtrail_client.audited_account
@@ -82,7 +82,7 @@ class cloudtrail_threat_detection_llm_jacking(Check):
if len(actions) / len(llm_jacking_actions) > threshold:
found_potential_llm_jacking = True
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = aws_identity_arn.split("/")[-1]
@@ -92,7 +92,7 @@ class cloudtrail_threat_detection_llm_jacking(Check):
findings.append(report)
if not found_potential_llm_jacking:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = cloudtrail_client.audited_account
@@ -123,7 +123,7 @@ class cloudtrail_threat_detection_privilege_escalation(Check):
if len(actions) / len(privilege_escalation_actions) > threshold:
found_potential_privilege_escalation = True
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = aws_identity_arn.split("/")[-1]
@@ -133,7 +133,7 @@ class cloudtrail_threat_detection_privilege_escalation(Check):
findings.append(report)
if not found_potential_privilege_escalation:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=cloudtrail_client.trails
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.region = cloudtrail_client.region
report.resource_id = cloudtrail_client.audited_account
@@ -8,9 +8,7 @@ class cloudwatch_alarm_actions_alarm_state_configured(Check):
def execute(self):
findings = []
for metric_alarm in cloudwatch_client.metric_alarms:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=metric_alarm
)
report = Check_Report_AWS(metadata=self.metadata(), resource=metric_alarm)
report.status = "PASS"
report.status_extended = f"CloudWatch metric alarm {metric_alarm.name} has actions configured for the ALARM state."
if not metric_alarm.alarm_actions:
@@ -8,9 +8,7 @@ class cloudwatch_alarm_actions_enabled(Check):
def execute(self):
findings = []
for metric_alarm in cloudwatch_client.metric_alarms:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=metric_alarm
)
report = Check_Report_AWS(metadata=self.metadata(), resource=metric_alarm)
report.status = "PASS"
report.status_extended = (
f"CloudWatch metric alarm {metric_alarm.name} has actions enabled."
@@ -26,9 +26,7 @@ class cloudwatch_changes_to_network_acls_alarm_configured(Check):
if cloudtrail_client.trails is not None:
if report is None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logs_client.log_groups
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.status = "FAIL"
report.status_extended = "No CloudWatch log groups found with metric filters or alarms associated."
report.region = logs_client.region
@@ -26,9 +26,7 @@ class cloudwatch_changes_to_network_gateways_alarm_configured(Check):
if cloudtrail_client.trails is not None:
if report is None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logs_client.log_groups
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.status = "FAIL"
report.status_extended = "No CloudWatch log groups found with metric filters or alarms associated."
report.region = logs_client.region
@@ -26,9 +26,7 @@ class cloudwatch_changes_to_network_route_tables_alarm_configured(Check):
if cloudtrail_client.trails is not None:
if report is None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logs_client.log_groups
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.status = "FAIL"
report.status_extended = "No CloudWatch log groups found with metric filters or alarms associated."
report.region = logs_client.region
@@ -26,9 +26,7 @@ class cloudwatch_changes_to_vpcs_alarm_configured(Check):
if cloudtrail_client.trails is not None:
if report is None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=logs_client.log_groups
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.status = "FAIL"
report.status_extended = "No CloudWatch log groups found with metric filters or alarms associated."
report.region = logs_client.region
@@ -6,9 +6,7 @@ class cloudwatch_cross_account_sharing_disabled(Check):
def execute(self):
findings = []
if iam_client.roles is not None:
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=iam_client.roles
)
report = Check_Report_AWS(metadata=self.metadata(), resource={})
report.status = "PASS"
report.status_extended = "CloudWatch doesn't allow cross-account sharing."
report.region = iam_client.region
@@ -16,9 +14,7 @@ class cloudwatch_cross_account_sharing_disabled(Check):
report.resource_id = iam_client.audited_account
for role in iam_client.roles:
if role.name == "CloudWatch-CrossAccountSharingRole":
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=role
)
report = Check_Report_AWS(metadata=self.metadata(), resource=role)
report.region = iam_client.region
report.status = "FAIL"
report.status_extended = (
@@ -7,9 +7,7 @@ class cloudwatch_log_group_kms_encryption_enabled(Check):
findings = []
if logs_client.log_groups:
for log_group in logs_client.log_groups.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=log_group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=log_group)
if log_group.kms_id:
report.status = "PASS"
report.status_extended = f"Log Group {log_group.name} does have AWS KMS key {log_group.kms_id} associated."
@@ -16,9 +16,7 @@ class cloudwatch_log_group_no_secrets_in_logs(Check):
"secrets_ignore_patterns", []
)
for log_group in logs_client.log_groups.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=log_group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=log_group)
report.status = "PASS"
report.status_extended = (
f"No secrets found in {log_group.name} log group."
@@ -25,9 +25,7 @@ class cloudwatch_log_group_not_publicly_accessible(Check):
if log_group.arn in resource or resource == "*":
public_log_groups.append(log_group.arn)
for log_group in logs_client.log_groups.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=log_group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=log_group)
report.status = "PASS"
report.status_extended = (
f"Log Group {log_group.name} is not publicly accessible."
@@ -12,9 +12,7 @@ class cloudwatch_log_group_retention_policy_specific_days_enabled(Check):
)
if logs_client.log_groups:
for log_group in logs_client.log_groups.values():
report = Check_Report_AWS(
metadata=self.metadata(), resource_metadata=log_group
)
report = Check_Report_AWS(metadata=self.metadata(), resource=log_group)
if (
log_group.never_expire is False
and log_group.retention_days < specific_retention_days

Some files were not shown because too many files have changed in this diff Show More