Compare commits

...

38 Commits

Author SHA1 Message Date
Daniel Barranquero
0a8a286850 merge branch 'master' into PRWLR-7205-migrate-fixers-to-new-class-structure 2025-07-15 12:19:43 +02:00
Daniel Barranquero
02b65a1471 fix: solve conflicts 2025-06-24 10:17:24 +02:00
Daniel Barranquero
82ab20deec feat(compute): add tests for gcp fixer 2025-06-24 10:01:07 +02:00
Daniel Barranquero
d7e3b1c760 feat(gcp): working version of gcp fixer 2025-06-23 13:14:25 +02:00
Daniel Barranquero
166e07939d feat(gcp): add first version of gcp tests 2025-06-23 12:33:51 +02:00
Daniel Barranquero
c5cf1c4bfb merge branch 'master' into PRWLR-5093-design-the-fixer-class 2025-06-23 10:20:06 +02:00
Daniel Barranquero
2147866229 feat(aws): add changelog 2025-06-12 13:05:25 +02:00
Daniel Barranquero
761c97100a chore(aws): change fixers structure 2025-06-12 12:35:40 +02:00
Daniel Barranquero
4fcb6b34e7 chore(ec2): change all ec2 fixers to new structure 2025-06-12 11:40:00 +02:00
Daniel Barranquero
07c5ae547f chore(aws): migrate fixers to new structure until ec2_ebs 2025-06-11 14:21:43 +02:00
Daniel Barranquero
09b33d05a3 fix vulture 2025-06-11 12:52:36 +02:00
Daniel Barranquero
6a7cfd175c chore(tests): improve tests 2025-06-11 12:47:42 +02:00
Daniel Barranquero
82543c0d63 fix(azure): change azure fixer tests 2025-06-11 09:45:32 +02:00
Daniel Barranquero
7360395263 feat(tests): add tests for new fixers 2025-06-10 19:15:16 +02:00
Daniel Barranquero
4ae790ee73 fix: tests with function apps 2025-06-10 11:17:54 +02:00
Daniel Barranquero
7a2d3db082 chore(app): fix app service tests 2025-06-09 16:35:11 +02:00
Daniel Barranquero
40934d34b2 fix: flake8 2025-06-09 13:38:16 +02:00
Daniel Barranquero
5c93372210 chore(tests): add tests for azure and m365 fixers 2025-06-09 13:32:47 +02:00
Daniel Barranquero
ffcc516f00 chore(kms): modify fixer test 2025-06-09 11:30:44 +02:00
Daniel Barranquero
9d4094e19e fix: remove unnecessary changes 2025-06-04 13:21:25 +02:00
Daniel Barranquero
00e491415f chore(app): new version of the fixer 2025-06-04 12:51:39 +02:00
Daniel Barranquero
e17cbed4b3 Merge branch 'PRWLR-7353-fix-app-function-ftps-deployment-disabled-check' into PRWLR-5093-design-the-fixer-class 2025-06-04 12:34:01 +02:00
Daniel Barranquero
d1e41f16ef fix: solve comments 2025-06-04 12:32:32 +02:00
Daniel Barranquero
a17c3f94fc chore(azure): add permissions to azure fixer info 2025-06-04 10:48:55 +02:00
Daniel Barranquero
70f8232747 Merge branch 'PRWLR-7353-fix-app-function-ftps-deployment-disabled-check' into PRWLR-5093-design-the-fixer-class 2025-06-04 09:47:06 +02:00
Daniel Barranquero
31189f0d11 chore(app): mantain none by default 2025-06-04 09:43:17 +02:00
Daniel Barranquero
5aaf6e4858 feat(app): add changelog 2025-06-04 09:29:14 +02:00
Daniel Barranquero
e05cc4cfab fix(app): change api call for app function ftps check 2025-06-03 17:57:52 +02:00
Daniel Barranquero
18a6f29593 feat(gcp): add first version of gcp fixers 2025-06-03 17:40:05 +02:00
Daniel Barranquero
fc826da50c chore(azure): add changes to azure fixers 2025-06-03 17:38:09 +02:00
Daniel Barranquero
b30ee077da merge branch 'master' into PRWLR-5093-design-the-fixer-class 2025-06-02 10:38:00 +02:00
Daniel Barranquero
efdd967763 feat(fixers): add first version of azure fixers 2025-05-23 11:07:38 +02:00
Daniel Barranquero
ee146cd43e feat(m365): add first fixer for m365 2025-05-21 14:00:34 +02:00
Daniel Barranquero
f40aea757e feat(fixers): add first version of M365 fixers 2025-05-21 10:24:59 +02:00
Daniel Barranquero
7db24f8cb7 Merge branch 'master' into PRWLR-5093-design-the-fixer-class 2025-05-20 13:14:59 +02:00
Daniel Barranquero
f78e5c9e33 feat(fixers): change classes structure 2025-05-20 09:41:14 +02:00
Daniel Barranquero
d91bbe1ef4 feat(fixer): add fixing and modify errors from the v1 2025-05-15 16:40:09 +02:00
Daniel Barranquero
c0d211492e feat(fixer): add poc for Fixer class 2025-05-15 13:57:29 +02:00
147 changed files with 5839 additions and 2942 deletions

View File

@@ -12,6 +12,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `vm_ensure_using_approved_images` check for Azure provider [(#8168)](https://github.com/prowler-cloud/prowler/pull/8168)
- `vm_scaleset_associated_load_balancer` check for Azure provider [(#8181)](https://github.com/prowler-cloud/prowler/pull/8181)
- Add `test_connection` method to GitHub provider [(#8248)](https://github.com/prowler-cloud/prowler/pull/8248)
- Migrate AWS fixers to new class structure [(#8009)](https://github.com/prowler-cloud/prowler/pull/8009)
### Changed
@@ -90,6 +91,9 @@ All notable changes to the **Prowler SDK** are documented in this file.
### Removed
- OCSF version number references to point always to the latest [(#8064)](https://github.com/prowler-cloud/prowler/pull/8064)
### Fixed
- Update SDK Azure call for ftps_state in the App Service. [(#7923)](https://github.com/prowler-cloud/prowler/pull/7923)
---
## [v5.7.5] (Prowler 5.7.5)

View File

@@ -31,7 +31,6 @@ from prowler.lib.check.check import (
print_fixers,
print_services,
remove_custom_checks_module,
run_fixer,
)
from prowler.lib.check.checks_loader import load_checks_to_execute
from prowler.lib.check.compliance import update_checks_metadata_with_compliance
@@ -42,6 +41,7 @@ from prowler.lib.check.custom_checks_metadata import (
)
from prowler.lib.check.models import CheckMetadata
from prowler.lib.cli.parser import ProwlerArgumentParser
from prowler.lib.fix.fixer import Fixer
from prowler.lib.logger import logger, set_logging_config
from prowler.lib.outputs.asff.asff import ASFF
from prowler.lib.outputs.compliance.aws_well_architected.aws_well_architected import (
@@ -300,6 +300,7 @@ def prowler():
output_options = M365OutputOptions(
args, bulk_checks_metadata, global_provider.identity
)
global_provider.set_output_options(output_options)
elif provider == "nhn":
output_options = NHNOutputOptions(
args, bulk_checks_metadata, global_provider.identity
@@ -332,11 +333,11 @@ def prowler():
)
# Prowler Fixer
if output_options.fixer:
if args.fixer:
print(f"{Style.BRIGHT}\nRunning Prowler Fixer, please wait...{Style.RESET_ALL}")
# Check if there are any FAIL findings
if any("FAIL" in finding.status for finding in findings):
fixed_findings = run_fixer(findings)
fixed_findings = Fixer.run_fixer(findings)
if not fixed_findings:
print(
f"{Style.BRIGHT}{Fore.RED}\nThere were findings to fix, but the fixer failed or it is not implemented for those findings yet. {Style.RESET_ALL}\n"

View File

@@ -298,91 +298,6 @@ def import_check(check_path: str) -> ModuleType:
return lib
def run_fixer(check_findings: list) -> int:
"""
Run the fixer for the check if it exists and there are any FAIL findings
Args:
check_findings (list): list of findings
Returns:
int: number of fixed findings
"""
try:
# Map findings to each check
findings_dict = {}
fixed_findings = 0
for finding in check_findings:
if finding.check_metadata.CheckID not in findings_dict:
findings_dict[finding.check_metadata.CheckID] = []
findings_dict[finding.check_metadata.CheckID].append(finding)
for check, findings in findings_dict.items():
# Check if there are any FAIL findings for the check
if any("FAIL" in finding.status for finding in findings):
try:
check_module_path = f"prowler.providers.{findings[0].check_metadata.Provider}.services.{findings[0].check_metadata.ServiceName}.{check}.{check}_fixer"
lib = import_check(check_module_path)
fixer = getattr(lib, "fixer")
except ModuleNotFoundError:
logger.error(f"Fixer method not implemented for check {check}")
else:
print(
f"\nFixing fails for check {Fore.YELLOW}{check}{Style.RESET_ALL}..."
)
for finding in findings:
if finding.status == "FAIL":
# Check what type of fixer is:
# - If it is a fixer for a specific resource and region
# - If it is a fixer for a specific region
# - If it is a fixer for a specific resource
if (
"region" in fixer.__code__.co_varnames
and "resource_id" in fixer.__code__.co_varnames
):
print(
f"\t{orange_color}FIXING{Style.RESET_ALL} {finding.resource_id} in {finding.region}... "
)
if fixer(
resource_id=finding.resource_id,
region=finding.region,
):
fixed_findings += 1
print(f"\t{Fore.GREEN}DONE{Style.RESET_ALL}")
else:
print(f"\t{Fore.RED}ERROR{Style.RESET_ALL}")
elif "region" in fixer.__code__.co_varnames:
print(
f"\t{orange_color}FIXING{Style.RESET_ALL} {finding.region}... "
)
if fixer(region=finding.region):
fixed_findings += 1
print(f"\t{Fore.GREEN}DONE{Style.RESET_ALL}")
else:
print(f"\t{Fore.RED}ERROR{Style.RESET_ALL}")
elif "resource_arn" in fixer.__code__.co_varnames:
print(
f"\t{orange_color}FIXING{Style.RESET_ALL} Resource {finding.resource_arn}... "
)
if fixer(resource_arn=finding.resource_arn):
fixed_findings += 1
print(f"\t{Fore.GREEN}DONE{Style.RESET_ALL}")
else:
print(f"\t{Fore.RED}ERROR{Style.RESET_ALL}")
else:
print(
f"\t{orange_color}FIXING{Style.RESET_ALL} Resource {finding.resource_id}... "
)
if fixer(resource_id=finding.resource_id):
fixed_findings += 1
print(f"\t\t{Fore.GREEN}DONE{Style.RESET_ALL}")
else:
print(f"\t\t{Fore.RED}ERROR{Style.RESET_ALL}")
return fixed_findings
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def execute_checks(
checks_to_execute: list,
global_provider: Any,

View File

@@ -72,6 +72,7 @@ Detailed documentation at https://docs.prowler.com
self.__init_config_parser__()
self.__init_custom_checks_metadata_parser__()
self.__init_third_party_integrations_parser__()
self.__init_fixer_parser__()
# Init Providers Arguments
init_providers_parser(self)
@@ -393,3 +394,12 @@ Detailed documentation at https://docs.prowler.com
action="store_true",
help="Send a summary of the execution with a Slack APP in your channel. Environment variables SLACK_API_TOKEN and SLACK_CHANNEL_NAME are required (see more in https://docs.prowler.cloud/en/latest/tutorials/integrations/#slack).",
)
def __init_fixer_parser__(self):
"""Initialize the fixer parser with its arguments"""
fixer_parser = self.common_providers_parser.add_argument_group("Fixer")
fixer_parser.add_argument(
"--fixer",
action="store_true",
help="Fix the failed findings that can be fixed by Prowler",
)

View File

219
prowler/lib/fix/fixer.py Normal file
View File

@@ -0,0 +1,219 @@
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Union
from colorama import Fore, Style
from prowler.lib.check.models import Check_Report
from prowler.lib.logger import logger
class Fixer(ABC):
"""Base class for all fixers"""
def __init__(
self,
description: str,
cost_impact: bool = False,
cost_description: Optional[str] = None,
):
"""
Initialize base fixer class.
Args:
description (str): Description of the fixer
cost_impact (bool): Whether the fixer has a cost impact
cost_description (Optional[str]): Description of the cost impact
"""
self._client = None
self.logger = logger
self.description = description
self.cost_impact = cost_impact
self.cost_description = cost_description
def _get_fixer_info(self) -> Dict:
"""Get fixer metadata"""
return {
"description": self.description,
"cost_impact": self.cost_impact,
"cost_description": self.cost_description,
}
@abstractmethod
def fix(self, finding: Optional[Check_Report] = None, **kwargs) -> bool:
"""
Main method that all fixers must implement.
Args:
finding (Optional[Check_Report]): Finding to fix
**kwargs: Additional arguments specific to each fixer
Returns:
bool: True if fix was successful, False otherwise
"""
@property
def client(self):
"""Lazy load of the client"""
return self._client
@classmethod
def get_fixer_for_finding(
cls,
finding: Check_Report,
) -> Optional["Fixer"]:
"""
Factory method to get the appropriate fixer for a finding.
Args:
finding (Check_Report): The finding to fix
credentials (Optional[Dict]): Optional credentials for isolated execution
session_config (Optional[Dict]): Optional session configuration
Returns:
Optional[Fixer]: An instance of the appropriate fixer or None if no fixer is found
"""
try:
# Extract check name from finding
check_name = finding.check_metadata.CheckID
if not check_name:
logger.error("Finding does not contain a check ID")
return None
# Convert check name to fixer class name
# Example: rds_instance_no_public_access -> RdsInstanceNoPublicAccessFixer
fixer_name = (
"".join(word.capitalize() for word in check_name.split("_")) + "Fixer"
)
# Get provider from finding
provider = finding.check_metadata.Provider
if not provider:
logger.error("Finding does not contain a provider")
return None
# Get service name from finding
service_name = finding.check_metadata.ServiceName
# Import the fixer class dynamically
try:
# Build the module path using the service name and check name
module_path = f"prowler.providers.{provider.lower()}.services.{service_name}.{check_name}.{check_name}_fixer"
module = __import__(module_path, fromlist=[fixer_name])
fixer_class = getattr(module, fixer_name)
return fixer_class()
except (ImportError, AttributeError):
print(
f"\n{Fore.YELLOW}No fixer available for check {check_name}{Style.RESET_ALL}"
)
return None
except Exception as e:
logger.error(f"Error getting fixer for finding: {str(e)}")
return None
@classmethod
def run_fixer(
cls,
findings: Union[Check_Report, List[Check_Report]],
) -> int:
"""
Method to execute the fixer on one or multiple findings.
Args:
findings (Union[Check_Report, List[Check_Report]]): A single finding or list of findings to fix
Returns:
int: Number of findings successfully fixed
"""
try:
# Handle single finding case
if isinstance(findings, Check_Report):
if findings.status != "FAIL":
return 0
check_id = findings.check_metadata.CheckID
if not check_id:
return 0
return cls.run_individual_fixer(check_id, [findings])
# Handle multiple findings case
fixed_findings = 0
findings_by_check = {}
# Group findings by check
for finding in findings:
if finding.status != "FAIL":
continue
check_id = finding.check_metadata.CheckID
if not check_id:
continue
if check_id not in findings_by_check:
findings_by_check[check_id] = []
findings_by_check[check_id].append(finding)
# Process each check
for check_id, check_findings in findings_by_check.items():
fixed_findings += cls.run_individual_fixer(check_id, check_findings)
return fixed_findings
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return 0
@classmethod
def run_individual_fixer(cls, check_id: str, findings: List[Check_Report]) -> int:
"""
Run the fixer for a specific check ID.
Args:
check_id (str): The check ID to fix
findings (List[Check_Report]): List of findings to process
Returns:
int: Number of findings successfully fixed
"""
try:
# Filter findings for this check_id and status FAIL
check_findings = [
finding
for finding in findings
if finding.check_metadata.CheckID == check_id
and finding.status == "FAIL"
]
if not check_findings:
return 0
# Get the fixer for this check
fixer = cls.get_fixer_for_finding(check_findings[0])
if not fixer:
return 0
# Print fixer information
print(f"\n{Fore.CYAN}Fixer Information for {check_id}:{Style.RESET_ALL}")
print(f"{Fore.CYAN}================================={Style.RESET_ALL}")
for key, value in fixer._get_fixer_info().items():
print(f"{Fore.CYAN}{key}: {Style.RESET_ALL}{value}")
print(f"{Fore.CYAN}================================={Style.RESET_ALL}\n")
print(
f"\nFixing fails for check {Fore.YELLOW}{check_id}{Style.RESET_ALL}..."
)
fixed_findings = 0
for finding in check_findings:
if fixer.fix(finding=finding):
fixed_findings += 1
print(f"\t{Fore.GREEN}DONE{Style.RESET_ALL}")
else:
print(f"\t{Fore.RED}ERROR{Style.RESET_ALL}")
return fixed_findings
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return 0

View File

@@ -159,14 +159,6 @@ def init_parser(self):
help="Scan unused services",
)
# Prowler Fixer
prowler_fixer_subparser = aws_parser.add_argument_group("Prowler Fixer")
prowler_fixer_subparser.add_argument(
"--fixer",
action="store_true",
help="Fix the failed findings that can be fixed by Prowler",
)
def validate_session_duration(session_duration: int) -> int:
"""validate_session_duration validates that the input session_duration is valid"""

View File

@@ -0,0 +1,101 @@
from typing import Dict, Optional
from colorama import Style
from prowler.config.config import orange_color
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.fix.fixer import Fixer
from prowler.lib.logger import logger
class AWSFixer(Fixer):
"""AWS specific fixer implementation"""
def __init__(
self,
description: str,
cost_impact: bool = False,
cost_description: Optional[str] = None,
service: str = "",
iam_policy_required: Optional[Dict] = None,
):
"""
Initialize AWS fixer with metadata.
Args:
description (str): Description of the fixer
cost_impact (bool): Whether the fixer has a cost impact
cost_description (Optional[str]): Description of the cost impact
service (str): AWS service name
iam_policy_required (Optional[Dict]): Required IAM policy for the fixer
"""
super().__init__(description, cost_impact, cost_description)
self.service = service
self.iam_policy_required = iam_policy_required or {}
def _get_fixer_info(self):
"""Each fixer must define its metadata"""
fixer_info = super()._get_fixer_info()
fixer_info["service"] = self.service
fixer_info["iam_policy_required"] = self.iam_policy_required
return fixer_info
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
AWS specific method to execute the fixer.
This method handles the printing of fixing status messages.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: Additional AWS-specific arguments (region, resource_id, resource_arn)
Returns:
bool: True if fixing was successful, False otherwise
"""
try:
# Get values either from finding or kwargs
region = None
resource_id = None
resource_arn = None
if finding:
region = finding.region if hasattr(finding, "region") else None
resource_id = (
finding.resource_id if hasattr(finding, "resource_id") else None
)
resource_arn = (
finding.resource_arn if hasattr(finding, "resource_arn") else None
)
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
resource_arn = kwargs.get("resource_arn")
# Print the appropriate message based on available information
if region and resource_id:
print(
f"\t{orange_color}FIXING {resource_id} in {region}...{Style.RESET_ALL}"
)
elif region:
print(f"\t{orange_color}FIXING {region}...{Style.RESET_ALL}")
elif resource_arn:
print(
f"\t{orange_color}FIXING Resource {resource_arn}...{Style.RESET_ALL}"
)
elif resource_id:
print(
f"\t{orange_color}FIXING Resource {resource_id}...{Style.RESET_ALL}"
)
else:
logger.error(
"Either finding or required kwargs (region, resource_id, resource_arn) must be provided"
)
return False
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,42 +1,69 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.accessanalyzer.accessanalyzer_client import (
accessanalyzer_client,
)
def fixer(region):
class AccessAnalyzerEnabledFixer(AWSFixer):
"""
Enable Access Analyzer in a region. Requires the access-analyzer:CreateAnalyzer permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "access-analyzer:CreateAnalyzer",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if Access Analyzer is enabled, False otherwise
Fixer for enabling Access Analyzer in a region.
"""
try:
regional_client = accessanalyzer_client.regional_clients[region]
regional_client.create_analyzer(
analyzerName=accessanalyzer_client.fixer_config.get(
"accessanalyzer_enabled", {}
).get("AnalyzerName", "DefaultAnalyzer"),
type=accessanalyzer_client.fixer_config.get(
"accessanalyzer_enabled", {}
).get("AnalyzerType", "ACCOUNT_UNUSED_ACCESS"),
def __init__(self):
super().__init__(
description="Enable Access Analyzer in a region",
cost_impact=True,
cost_description="Enabling Access Analyzer may incur costs for policy and resource analysis, especially in large accounts or organizations. See AWS Access Analyzer pricing.",
service="accessanalyzer",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "access-analyzer:CreateAnalyzer",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable Access Analyzer in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if Access Analyzer is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("Region is required")
# Show the fixing message
super().fix(region=region)
regional_client = accessanalyzer_client.regional_clients[region]
regional_client.create_analyzer(
analyzerName=accessanalyzer_client.fixer_config.get(
"accessanalyzer_enabled", {}
).get("AnalyzerName", "DefaultAnalyzer"),
type=accessanalyzer_client.fixer_config.get(
"accessanalyzer_enabled", {}
).get("AnalyzerType", "ACCOUNT_UNUSED_ACCESS"),
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,61 +1,83 @@
import json
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.awslambda.awslambda_client import awslambda_client
def fixer(resource_id: str, region: str) -> bool:
class LambdaFunctionNotPubliclyAccessibleFixer(AWSFixer):
"""
Remove the Lambda function's resource-based policy to prevent public access and add a new permission for the account.
Specifically, this fixer deletes all permission statements associated with the Lambda function's policy and then adds a new permission.
Requires the lambda:RemovePermission and lambda:AddPermission permissions.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:RemovePermission",
"Resource": "*"
Fixer for removing public access from Lambda function policies.
"""
def __init__(self):
super().__init__(
description="Remove public access from Lambda function's resource-based policy and add a new permission for the account.",
cost_impact=False,
cost_description=None,
service="awslambda",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:RemovePermission",
"Resource": "*",
},
{
"Effect": "Allow",
"Action": "lambda:AddPermission",
"Resource": "*",
},
],
},
{
"Effect": "Allow",
"Action": "lambda:AddPermission",
"Resource": "*"
}
]
}
Args:
resource_id (str): The Lambda function name or ARN.
region (str): AWS region where the Lambda function exists.
Returns:
bool: True if the operation is successful (policy removed and permission added), False otherwise.
"""
try:
account_id = awslambda_client.audited_account
regional_client = awslambda_client.regional_clients[region]
policy_response = regional_client.get_policy(FunctionName=resource_id)
policy = json.loads(policy_response.get("Policy"))
for statement in policy.get("Statement", []):
statement_id = statement.get("Sid")
if statement_id:
regional_client.remove_permission(
FunctionName=resource_id, StatementId=statement_id
)
regional_client.add_permission(
FunctionName=resource_id,
StatementId="ProwlerFixerStatement",
Principal=account_id,
Action="lambda:InvokeFunction",
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove the Lambda function's resource-based policy to prevent public access and add a new permission for the account.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
account_id = awslambda_client.audited_account
regional_client = awslambda_client.regional_clients[region]
policy_response = regional_client.get_policy(FunctionName=resource_id)
policy = json.loads(policy_response.get("Policy"))
for statement in policy.get("Statement", []):
statement_id = statement.get("Sid")
if statement_id:
regional_client.remove_permission(
FunctionName=resource_id, StatementId=statement_id
)
regional_client.add_permission(
FunctionName=resource_id,
StatementId="ProwlerFixerStatement",
Principal=account_id,
Action="lambda:InvokeFunction",
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,52 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.cloudtrail.cloudtrail_client import (
cloudtrail_client,
)
from prowler.providers.aws.services.s3.s3_client import s3_client
def fixer(resource_id: str, region: str) -> bool:
class CloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer(AWSFixer):
"""
Modify the CloudTrail's associated S3 bucket's public access settings to ensure the bucket is not publicly accessible.
Specifically, this fixer configures the S3 bucket's public access block settings to block all public access.
Requires the s3:PutBucketPublicAccessBlock permissions.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketPublicAccessBlock",
"Resource": "*"
}
]
}
Args:
resource_id (str): The CloudTrail name.
region (str): AWS region where the CloudTrail and S3 bucket exist.
Returns:
bool: True if the operation is successful (policy and ACL updated), False otherwise.
Fixer for ensuring CloudTrail's associated S3 bucket is not publicly accessible.
"""
try:
regional_client = s3_client.regional_clients[region]
for trail in cloudtrail_client.trails.values():
if trail.name == resource_id:
trail_bucket = trail.s3_bucket
regional_client.put_public_access_block(
Bucket=trail_bucket,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Modify the CloudTrail's associated S3 bucket's public access settings to ensure the bucket is not publicly accessible.",
cost_impact=False,
cost_description=None,
service="cloudtrail",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketPublicAccessBlock",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Modify the CloudTrail's associated S3 bucket's public access settings to ensure the bucket is not publicly accessible.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = s3_client.regional_clients[region]
for trail in cloudtrail_client.trails.values():
if trail.name == resource_id:
trail_bucket = trail.s3_bucket
regional_client.put_public_access_block(
Bucket=trail_bucket,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,59 +1,84 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.cloudtrail.cloudtrail_client import (
cloudtrail_client,
)
def fixer(region):
class CloudtrailMultiRegionEnabledFixer(AWSFixer):
"""
NOTE: Define the S3 bucket name in the fixer_config.yaml file.
Enable CloudTrail in a region. Requires the cloudtrail:CreateTrail permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudtrail:CreateTrail",
"Resource": "*"
Fixer for enabling CloudTrail as a multi-region trail in a region.
"""
def __init__(self):
super().__init__(
description="Enable CloudTrail as a multi-region trail in a region.",
cost_impact=False,
cost_description=None,
service="cloudtrail",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudtrail:CreateTrail",
"Resource": "*",
}
],
},
)
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable CloudTrail as a multi-region trail in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if CloudTrail is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("Region is required")
super().fix(region=region)
cloudtrail_fixer_config = cloudtrail_client.fixer_config.get(
"cloudtrail_multi_region_enabled", {}
)
regional_client = cloudtrail_client.regional_clients[region]
args = {
"Name": cloudtrail_fixer_config.get("TrailName", "DefaultTrail"),
"S3BucketName": cloudtrail_fixer_config.get("S3BucketName"),
"IsMultiRegionTrail": cloudtrail_fixer_config.get(
"IsMultiRegionTrail", True
),
"EnableLogFileValidation": cloudtrail_fixer_config.get(
"EnableLogFileValidation", True
),
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if CloudTrail is enabled, False otherwise
"""
try:
cloudtrail_fixer_config = cloudtrail_client.fixer_config.get(
"cloudtrail_multi_region_enabled", {}
)
regional_client = cloudtrail_client.regional_clients[region]
args = {
"Name": cloudtrail_fixer_config.get("TrailName", "DefaultTrail"),
"S3BucketName": cloudtrail_fixer_config.get("S3BucketName"),
"IsMultiRegionTrail": cloudtrail_fixer_config.get(
"IsMultiRegionTrail", True
),
"EnableLogFileValidation": cloudtrail_fixer_config.get(
"EnableLogFileValidation", True
),
}
if cloudtrail_fixer_config.get("CloudWatchLogsLogGroupArn"):
args["CloudWatchLogsLogGroupArn"] = cloudtrail_fixer_config.get(
"CloudWatchLogsLogGroupArn"
if cloudtrail_fixer_config.get("CloudWatchLogsLogGroupArn"):
args["CloudWatchLogsLogGroupArn"] = cloudtrail_fixer_config.get(
"CloudWatchLogsLogGroupArn"
)
if cloudtrail_fixer_config.get("CloudWatchLogsRoleArn"):
args["CloudWatchLogsRoleArn"] = cloudtrail_fixer_config.get(
"CloudWatchLogsRoleArn"
)
if cloudtrail_fixer_config.get("KmsKeyId"):
args["KmsKeyId"] = cloudtrail_fixer_config.get("KmsKeyId")
regional_client.create_trail(**args)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
if cloudtrail_fixer_config.get("CloudWatchLogsRoleArn"):
args["CloudWatchLogsRoleArn"] = cloudtrail_fixer_config.get(
"CloudWatchLogsRoleArn"
)
if cloudtrail_fixer_config.get("KmsKeyId"):
args["KmsKeyId"] = cloudtrail_fixer_config.get("KmsKeyId")
regional_client.create_trail(**args)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
return False

View File

@@ -1,71 +1,94 @@
import json
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_arn: str) -> bool:
class CloudtrailThreatDetectionEnumerationFixer(AWSFixer):
"""
Fixer for restricting access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Requires the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
def __init__(self):
super().__init__(
description="Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.",
cost_impact=False,
cost_description=None,
service="cloudtrail",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
],
"Resource": "*",
}
],
"Resource": "*"
}
]
}
Args:
resource_arn (str): The ARN of the compromised AWS entity (IAM User or Role).
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
},
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix (should have resource_arn)
**kwargs: resource_arn (if finding is not provided)
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if finding:
resource_arn = getattr(finding, "resource_arn", None)
else:
resource_arn = kwargs.get("resource_arn")
if not resource_arn:
raise ValueError("resource_arn is required")
super().fix(resource_arn=resource_arn)
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,71 +1,94 @@
import json
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_arn: str) -> bool:
class CloudtrailThreatDetectionLlmJackingFixer(AWSFixer):
"""
Fixer for restricting access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Requires the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
def __init__(self):
super().__init__(
description="Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.",
cost_impact=False,
cost_description=None,
service="cloudtrail",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
],
"Resource": "*",
}
],
"Resource": "*"
}
]
}
Args:
resource_arn (str): The ARN of the compromised AWS entity (IAM User or Role).
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
},
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix (should have resource_arn)
**kwargs: resource_arn (if finding is not provided)
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if finding:
resource_arn = getattr(finding, "resource_arn", None)
else:
resource_arn = kwargs.get("resource_arn")
if not resource_arn:
raise ValueError("resource_arn is required")
super().fix(resource_arn=resource_arn)
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,71 +1,94 @@
import json
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_arn: str) -> bool:
class CloudtrailThreatDetectionPrivilegeEscalationFixer(AWSFixer):
"""
Fixer for restricting access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Requires the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
def __init__(self):
super().__init__(
description="Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.",
cost_impact=False,
cost_description=None,
service="cloudtrail",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PutUserPolicy",
"iam:PutRolePolicy",
],
"Resource": "*",
}
],
"Resource": "*"
}
]
}
Args:
resource_arn (str): The ARN of the compromised AWS entity (IAM User or Role).
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
},
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Restricts access to a compromised AWS entity by attaching a deny-all inline policy to the user or role.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix (should have resource_arn)
**kwargs: resource_arn (if finding is not provided)
Returns:
bool: True if the fix was applied successfully, False otherwise.
"""
try:
if finding:
resource_arn = getattr(finding, "resource_arn", None)
else:
resource_arn = kwargs.get("resource_arn")
if not resource_arn:
raise ValueError("resource_arn is required")
super().fix(resource_arn=resource_arn)
if ":user/" in resource_arn:
entity_type = "user"
entity_name = resource_arn.split("/")[-1]
elif ":role/" in resource_arn:
entity_type = "role"
entity_name = resource_arn.split("/")[-1]
else:
return False
deny_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}],
}
policy_name = "DenyAllAccess"
if entity_type == "user":
iam_client.client.put_user_policy(
UserName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to user {entity_name}")
elif entity_type == "role":
iam_client.client.put_role_policy(
RoleName=entity_name,
PolicyName=policy_name,
PolicyDocument=json.dumps(deny_policy),
)
logger.info(f"Applied Deny policy to role {entity_name}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,59 +1,81 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.codeartifact.codeartifact_client import (
codeartifact_client,
)
def fixer(resource_id: str, region: str) -> bool:
class CodeartifactPackagesExternalPublicPublishingDisabledFixer(AWSFixer):
"""
Modify the CodeArtifact package's configuration to restrict public access.
Specifically, this fixer changes the package's configuration to block public access by
setting restrictions on the "publish" and "upstream" actions.
Requires the codeartifact:PutPackageOriginConfiguration permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codeartifact:PutPackageOriginConfiguration",
"Resource": "*"
}
]
}
Args:
resource_id (str): The CodeArtifact package name in the format "domain_name/package_name".
region (str): AWS region where the CodeArtifact package exists.
Returns:
bool: True if the operation is successful (configuration updated), False otherwise.
Fixer for modifying the CodeArtifact package's configuration to restrict public access.
"""
try:
domain_name, package_name = resource_id.split("/")
regional_client = codeartifact_client.regional_clients[region]
for repository in codeartifact_client.repositories.values():
if repository.domain_name == domain_name:
for package in repository.packages:
if package.name == package_name:
publish_value = (
package.origin_configuration.restrictions.publish.value
)
regional_client.put_package_origin_configuration(
domain=domain_name,
repository=repository.name,
format=package.format,
package=package_name,
restrictions={
"publish": publish_value,
"upstream": "BLOCK",
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Modify the CodeArtifact package's configuration to restrict public access.",
cost_impact=False,
cost_description=None,
service="codeartifact",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codeartifact:PutPackageOriginConfiguration",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Modify the CodeArtifact package's configuration to restrict public access.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful (configuration updated), False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
domain_name, package_name = resource_id.split("/")
regional_client = codeartifact_client.regional_clients[region]
for repository in codeartifact_client.repositories.values():
if repository.domain_name == domain_name:
for package in repository.packages:
if package.name == package_name:
publish_value = (
package.origin_configuration.restrictions.publish.value
)
regional_client.put_package_origin_configuration(
domain=domain_name,
repository=repository.name,
format=package.format,
package=package_name,
restrictions={
"publish": publish_value,
"upstream": "BLOCK",
},
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,42 +1,67 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.documentdb.documentdb_client import (
documentdb_client,
)
def fixer(resource_id: str, region: str) -> bool:
class DocumentdbClusterPublicSnapshotFixer(AWSFixer):
"""
Modify the attributes of a DocumentDB cluster snapshot to remove public access.
Specifically, this fixer removes the 'all' value from the 'restore' attribute to
prevent the snapshot from being publicly accessible. Requires the rds:ModifyDBClusterSnapshotAttribute permissions.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*"
}
]
}
Args:
resource_id (str): The DB cluster snapshot identifier.
region (str): AWS region where the snapshot exists.
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
Fixer for modifying the attributes of a DocumentDB cluster snapshot to remove public access.
"""
try:
regional_client = documentdb_client.regional_clients[region]
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
def __init__(self):
super().__init__(
description="Modify the attributes of a DocumentDB cluster snapshot to remove public access.",
cost_impact=False,
cost_description=None,
service="documentdb",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Modify the attributes of a DocumentDB cluster snapshot to remove public access.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = documentdb_client.regional_clients[region]
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,40 +1,64 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
def fixer(resource_id: str, region: str) -> bool:
class Ec2AmiPublicFixer(AWSFixer):
"""
Modify the attributes of an EC2 AMI to remove public access.
Specifically, this fixer removes the 'all' value from the 'LaunchPermission' attribute
to prevent the AMI from being publicly accessible.
Requires the ec2:ModifyImageAttribute permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifyImageAttribute",
"Resource": "*"
}
]
}
Args:
resource_id (str): The ID of the EC2 AMI to make private.
region (str): AWS region where the AMI exists.
Returns:
bool: True if the operation is successful (the AMI is no longer publicly accessible), False otherwise.
Fixer for modifying the attributes of an EC2 AMI to remove public access.
"""
try:
regional_client = ec2_client.regional_clients[region]
regional_client.modify_image_attribute(
ImageId=resource_id,
LaunchPermission={"Remove": [{"Group": "all"}]},
def __init__(self):
super().__init__(
description="Modify the attributes of an EC2 AMI to remove public access.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifyImageAttribute",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Modify the attributes of an EC2 AMI to remove public access.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful (the AMI is no longer publicly accessible), False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = ec2_client.regional_clients[region]
regional_client.modify_image_attribute(
ImageId=resource_id,
LaunchPermission={"Remove": [{"Group": "all"}]},
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,34 +1,60 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
def fixer(region):
class Ec2EbsDefaultEncryptionFixer(AWSFixer):
"""
Enable EBS encryption by default in a region. NOTE: Custom KMS keys for EBS Default Encryption may be overwritten.
Requires the ec2:EnableEbsEncryptionByDefault permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:EnableEbsEncryptionByDefault",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if EBS encryption by default is enabled, False otherwise
Fixer to enable EBS encryption by default in a region.
"""
try:
regional_client = ec2_client.regional_clients[region]
return regional_client.enable_ebs_encryption_by_default()[
"EbsEncryptionByDefault"
]
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Enable EBS encryption by default in a region. NOTE: Custom KMS keys for EBS Default Encryption may be overwritten.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:EnableEbsEncryptionByDefault",
"Resource": "*",
}
],
},
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable EBS encryption by default in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if EBS encryption by default is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("Region is required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
return regional_client.enable_ebs_encryption_by_default()[
"EbsEncryptionByDefault"
]
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,41 +1,66 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
def fixer(resource_id: str, region: str) -> bool:
class Ec2EbsPublicSnapshotFixer(AWSFixer):
"""
Modify the attributes of an EBS snapshot to remove public access.
Specifically, this fixer removes the 'all' value from the 'createVolumePermission' attribute to
prevent the snapshot from being publicly accessible. Requires the ec2:ModifySnapshotAttribute permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifySnapshotAttribute",
"Resource": "*"
}
]
}
Args:
resource_id (str): The snapshot identifier.
region (str): AWS region where the snapshot exists.
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
Fixer for modifying the attributes of an EBS snapshot to remove public access.
"""
try:
regional_client = ec2_client.regional_clients[region]
regional_client.modify_snapshot_attribute(
SnapshotId=resource_id,
Attribute="createVolumePermission",
OperationType="remove",
GroupNames=["all"],
def __init__(self):
super().__init__(
description="Modify the attributes of an EBS snapshot to remove public access.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifySnapshotAttribute",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Modify the attributes of an EBS snapshot to remove public access.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = ec2_client.regional_clients[region]
regional_client.modify_snapshot_attribute(
SnapshotId=resource_id,
Attribute="createVolumePermission",
OperationType="remove",
GroupNames=["all"],
)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,38 +1,66 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
def fixer(region):
class Ec2EbsSnapshotAccountBlockPublicAccessFixer(AWSFixer):
"""
Enable EBS snapshot block public access in a region.
Requires the ec2:EnableSnapshotBlockPublicAccess permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:EnableSnapshotBlockPublicAccess",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if EBS snapshot block public access is enabled, False otherwise
Fixer to enable EBS snapshot block public access in a region.
"""
try:
regional_client = ec2_client.regional_clients[region]
state = ec2_client.fixer_config.get(
"ec2_ebs_snapshot_account_block_public_access", {}
).get("State", "block-all-sharing")
return (
regional_client.enable_snapshot_block_public_access(State=state)["State"]
== state
def __init__(self):
super().__init__(
description="Enable EBS snapshot block public access in a region.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:EnableSnapshotBlockPublicAccess",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable EBS snapshot block public access in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if EBS snapshot block public access is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("Region is required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
state = ec2_client.fixer_config.get(
"ec2_ebs_snapshot_account_block_public_access", {}
).get("State", "block-all-sharing")
return (
regional_client.enable_snapshot_block_public_access(State=state)[
"State"
]
== state
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,35 +1,60 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
def fixer(region):
class Ec2InstanceAccountImdsv2EnabledFixer(AWSFixer):
"""
Enable IMDSv2 for EC2 instances in the specified region.
Requires the ec2:ModifyInstanceMetadataDefaults permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifyInstanceMetadataDefaults",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if IMDSv2 is enabled, False otherwise
Fixer to enable IMDSv2 for EC2 instances in a region.
"""
try:
regional_client = ec2_client.regional_clients[region]
return regional_client.modify_instance_metadata_defaults(HttpTokens="required")[
"Return"
]
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Enable IMDSv2 for EC2 instances in a region.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:ModifyInstanceMetadataDefaults",
"Resource": "*",
}
],
},
)
return False
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IMDSv2 for EC2 instances in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if IMDSv2 is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("Region is required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
return regional_client.modify_instance_metadata_defaults(
HttpTokens="required"
)["Return"]
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortCassandraExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Cassandra ports (7000, 7001, 7199, 9042, 9160) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Cassandra ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Cassandra ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [7000, 7001, 7199, 9042, 9160]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Cassandra ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Cassandra ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [7000, 7001, 7199, 9042, 9160]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortCifsExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing CIFS ports (139, 445) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies CIFS ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing CIFS ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [139, 445]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing CIFS ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing CIFS ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [139, 445]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortElasticsearchKibanaExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Elasticsearch and Kibana ports (9200, 9300, 5601)
from any address (0.0.0.0/0) for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies those ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Elasticsearch and Kibana ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [9200, 9300, 5601]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Elasticsearch and Kibana ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Elasticsearch and Kibana ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [9200, 9300, 5601]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortFtpExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing FTP ports (20, 21) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies FTP ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing FTP ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [20, 21]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing FTP ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing FTP ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [20, 21]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortKafkaExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Kafka ports (9092) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Kafka ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Kafka ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [9092]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Kafka ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Kafka ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [9092]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortKerberosExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Kerberos ports (88, 464, 749, 750) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Kerberos ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Kerberos ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [88, 464, 749, 750]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Kerberos ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Kerberos ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [88, 464, 749, 750]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortLdapExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing LDAP ports (389, 636) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies LDAP ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing LDAP ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [389, 636]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing LDAP ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing LDAP ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [389, 636]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortMemcachedExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Memcached ports (11211) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Memcached ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Memcached ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [11211]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Memcached ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Memcached ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [11211]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortMongodbExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing MongoDB ports (27017, 27018) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies MongoDB ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing MongoDB ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [27017, 27018]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing MongoDB ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing MongoDB ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [27017, 27018]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortMysqlExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing MySQL ports (3306) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies MySQL ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing MySQL ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [3306]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing MySQL ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing MySQL ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [3306]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortOracleExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Oracle ports (1521, 2483, 2484) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Oracle ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Oracle ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [1521, 2483, 2484]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Oracle ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Oracle ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [1521, 2483, 2484]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortPostgresqlExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing PostgreSQL ports (5432) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies PostgreSQL ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing PostgreSQL ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [5432]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing PostgreSQL ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing PostgreSQL ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [5432]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortRdpExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing RDP ports (3389) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies RDP ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing RDP ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [3389]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing RDP ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing RDP ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [3389]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortRedisExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Redis ports (6379) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Redis ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Redis ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [6379]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Redis ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Redis ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [6379]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortSqlserverExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing SQLServer ports (1433, 1434) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies SQLServer ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing SQLServer ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [1433, 1434]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing SQLServer ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing SQLServer ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [1433, 1434]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortSshExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing SSH ports (22) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies SSH ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing SSH ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [22]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing SSH ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing SSH ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [22]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,51 +1,75 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2InstancePortTelnetExposedToInternetFixer(AWSFixer):
"""
Revokes any ingress rule allowing Telnet ports (23) from any address (0.0.0.0/0)
for the EC2 instance's security groups.
This fixer will only be triggered if the check identifies Telnet ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The EC2 instance ID.
region (str): The AWS region where the EC2 instance exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing Telnet ports from any address for EC2 instances' security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = [23]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing Telnet ports from any address for EC2 instances' security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing Telnet ports from any address for EC2 instances' security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = [23]
for instance in ec2_client.instances:
if instance.id == resource_id:
for sg in ec2_client.security_groups.values():
if sg.id in instance.security_groups:
for ingress_rule in sg.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=sg.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,52 +1,76 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
def fixer(resource_id: str, region: str) -> bool:
class Ec2SecuritygroupAllowIngressFromInternetToHighRiskTcpPortsFixer(AWSFixer):
"""
Revokes any ingress rule allowing high risk ports (25, 110, 135, 143, 445, 3000, 4333, 5000, 5500, 8080, 8088)
from any address (0.0.0.0/0) for the security groups.
This fixer will only be triggered if the check identifies high risk ports open to the Internet.
Requires the ec2:RevokeSecurityGroupIngress permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*"
}
]
}
Args:
resource_id (str): The Security Group ID.
region (str): The AWS region where the Security Group exists.
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
Fixer to revoke ingress rules allowing high risk ports from any address for security groups.
"""
try:
regional_client = ec2_client.regional_clients[region]
check_ports = ec2_client.audit_config.get(
"ec2_high_risk_ports",
[25, 110, 135, 143, 445, 3000, 4333, 5000, 5500, 8080, 8088],
)
for security_group in ec2_client.security_groups.values():
if security_group.id == resource_id:
for ingress_rule in security_group.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=security_group.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Revoke ingress rules allowing high risk ports from any address for security groups.",
cost_impact=False,
cost_description=None,
service="ec2",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RevokeSecurityGroupIngress",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Revoke ingress rules allowing high risk ports from any address for security groups.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (ingress rule revoked), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ec2_client.regional_clients[region]
check_ports = ec2_client.audit_config.get(
"ec2_high_risk_ports",
[25, 110, 135, 143, 445, 3000, 4333, 5000, 5500, 8080, 8088],
)
for security_group in ec2_client.security_groups.values():
if security_group.id == resource_id:
for ingress_rule in security_group.ingress_rules:
if check_security_group(
ingress_rule, "tcp", check_ports, any_address=True
):
regional_client.revoke_security_group_ingress(
GroupId=security_group.id,
IpPermissions=[ingress_rule],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,38 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.ecr.ecr_client import ecr_client
def fixer(resource_id: str, region: str) -> bool:
class EcrRepositoriesNotPubliclyAccessibleFixer(AWSFixer):
"""
Modify the ECR repository's policy to remove public access.
Specifically, this fixer delete the policy that had public access.
Requires the ecr:DeleteRepositoryPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ecr:DeleteRepositoryPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): The ECR repository name.
region (str): AWS region where the ECR repository exists.
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
Fixer to remove public access from ECR repositories by deleting their policy.
"""
try:
regional_client = ecr_client.regional_clients[region]
regional_client.delete_repository_policy(repositoryName=resource_id)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Remove public access from ECR repositories by deleting their policy.",
cost_impact=False,
cost_description=None,
service="ecr",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ecr:DeleteRepositoryPolicy",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from ECR repositories by deleting their policy.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = ecr_client.regional_clients[region]
regional_client.delete_repository_policy(repositoryName=resource_id)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,38 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.glacier.glacier_client import glacier_client
def fixer(resource_id: str, region: str) -> bool:
class GlacierVaultsPolicyPublicAccessFixer(AWSFixer):
"""
Modify the Glacier vault's policy to remove public access.
Specifically, this fixer delete the vault policy that has public access.
Requires the glacier:DeleteVaultAccessPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "glacier:DeleteVaultAccessPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): The Glacier vault name.
region (str): AWS region where the Glacier vault exists.
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
Fixer to remove public access from Glacier vaults by deleting their access policy.
"""
try:
regional_client = glacier_client.regional_clients[region]
regional_client.delete_vault_access_policy(vaultName=resource_id)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Remove public access from Glacier vaults by deleting their access policy.",
cost_impact=False,
cost_description=None,
service="glacier",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "glacier:DeleteVaultAccessPolicy",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from Glacier vaults by deleting their access policy.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id, region (if finding is not provided)
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
"""
try:
if finding:
resource_id = finding.resource_id
region = finding.region
else:
resource_id = kwargs.get("resource_id")
region = kwargs.get("region")
if not resource_id or not region:
raise ValueError("resource_id and region are required")
super().fix(region=region)
regional_client = glacier_client.regional_clients[region]
regional_client.delete_vault_access_policy(vaultName=resource_id)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,33 +1,60 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.guardduty.guardduty_client import guardduty_client
def fixer(region):
class GuarddutyIsEnabledFixer(AWSFixer):
"""
Enable GuardDuty in a region. Requires the guardduty:CreateDetector permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "guardduty:CreateDetector",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if GuardDuty is enabled, False otherwise
Fixer to enable GuardDuty in a region.
"""
try:
regional_client = guardduty_client.regional_clients[region]
regional_client.create_detector(Enable=True)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Enable GuardDuty in a region.",
cost_impact=True,
cost_description="Enabling GuardDuty incurs costs based on the volume of logs and events analyzed. Charges apply per GB of data processed and for threat detection features. See AWS GuardDuty pricing.",
service="guardduty",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "guardduty:CreateDetector",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable GuardDuty in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if GuardDuty is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("region is required")
super().fix(region=region)
regional_client = guardduty_client.regional_clients[region]
regional_client.create_detector(Enable=True)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyExpiresPasswordsWithin90DaysOrLessFixer(AWSFixer):
"""
Enable IAM password policy to expire passwords within 90 days or less or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to expire passwords within 90 days or less (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.fixer_config.get("iam_password_policy", {}).get(
"MaxPasswordAge", 90
),
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to expire passwords within 90 days or less (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to expire passwords within 90 days or less (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("MaxPasswordAge", 90),
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyLowercaseFixer(AWSFixer):
"""
Enable IAM password policy to require lowercase characters or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to require lowercase characters (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireLowercaseCharacters", True),
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to require lowercase characters (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to require lowercase characters (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireLowercaseCharacters", True),
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyMinimumLength14Fixer(AWSFixer):
"""
Enable IAM password policy to require a minimum password length of 14 characters or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to require a minimum password length of 14 characters (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("MinimumPasswordLength", 14),
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to require a minimum password length of 14 characters (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to require a minimum password length of 14 characters (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("MinimumPasswordLength", 14),
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyNumberFixer(AWSFixer):
"""
Enable IAM password policy to require numbers or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to require numbers (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.fixer_config.get("iam_password_policy", {}).get(
"RequireNumbers", True
),
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to require numbers (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to require numbers (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireNumbers", True),
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyReuse24Fixer(AWSFixer):
"""
Enable IAM password policy to prevent reusing the 24 previous passwords or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to prevent reusing the 24 previous passwords (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("PasswordReusePrevention", 24),
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to prevent reusing the 24 previous passwords (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to prevent reusing the 24 previous passwords (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("PasswordReusePrevention", 24),
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicySymbolFixer(AWSFixer):
"""
Enable IAM password policy to require symbols or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to require symbols (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.fixer_config.get("iam_password_policy", {}).get(
"RequireSymbols", True
),
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to require symbols (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to require symbols (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireSymbols", True),
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.password_policy.uppercase,
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,45 +1,71 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.iam.iam_client import iam_client
def fixer(resource_id: str) -> bool:
class IamPasswordPolicyUppercaseFixer(AWSFixer):
"""
Enable IAM password policy to require uppercase characters or the configurable value in prowler/config/fixer_config.yaml.
Requires the iam:UpdateAccountPasswordPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): AWS account ID
Returns:
bool: True if IAM password policy is updated, False otherwise
Fixer to enable IAM password policy to require uppercase characters (or configurable value).
"""
try:
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireUppercaseCharacters", True),
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
def __init__(self):
super().__init__(
description="Enable IAM password policy to require uppercase characters (or configurable value).",
cost_impact=False,
cost_description=None,
service="iam",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateAccountPasswordPolicy",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable IAM password policy to require uppercase characters (or configurable value).
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if IAM password policy is updated, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
iam_client.client.update_account_password_policy(
MinimumPasswordLength=iam_client.password_policy.length,
RequireSymbols=iam_client.password_policy.symbols,
RequireNumbers=iam_client.password_policy.numbers,
RequireUppercaseCharacters=iam_client.fixer_config.get(
"iam_password_policy", {}
).get("RequireUppercaseCharacters", True),
RequireLowercaseCharacters=iam_client.password_policy.lowercase,
AllowUsersToChangePassword=iam_client.password_policy.allow_change,
MaxPasswordAge=iam_client.password_policy.max_age,
PasswordReusePrevention=iam_client.password_policy.reuse_prevention,
HardExpiry=iam_client.password_policy.hard_expiry,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,36 +1,74 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.kms.kms_client import kms_client
def fixer(resource_id: str, region: str) -> bool:
class KmsCmkNotDeletedUnintentionallyFixer(AWSFixer):
"""
Cancel the scheduled deletion of a KMS key.
Specifically, this fixer calls the 'cancel_key_deletion' method to restore the KMS key's availability if it is marked for deletion.
Requires the kms:CancelKeyDeletion permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:CancelKeyDeletion",
"Resource": "*"
}
]
}
Args:
resource_id (str): The ID of the KMS key to cancel the deletion for.
region (str): AWS region where the KMS key exists.
Returns:
bool: True if the operation is successful (deletion cancellation is completed), False otherwise.
Fixer for KMS keys marked for deletion.
This fixer cancels the scheduled deletion of KMS keys.
"""
try:
regional_client = kms_client.regional_clients[region]
regional_client.cancel_key_deletion(KeyId=resource_id)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
"""
Initialize KMS fixer.
"""
super().__init__(
description="Cancel the scheduled deletion of a KMS key",
cost_impact=False,
cost_description=None,
service="kms",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:CancelKeyDeletion",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Cancel the scheduled deletion of a KMS key.
This fixer calls the 'cancel_key_deletion' method to restore the KMS key's availability
if it is marked for deletion.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: Additional arguments (region and resource_id are required if finding is not provided)
Returns:
bool: True if the operation is successful (deletion cancellation is completed), False otherwise
"""
try:
# Get region and resource_id either from finding or kwargs
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("Region and resource_id are required")
# Show the fixing message
super().fix(region=region, resource_id=resource_id)
# Get the client for this region
regional_client = kms_client.regional_clients[region]
# Cancel key deletion
regional_client.cancel_key_deletion(KeyId=resource_id)
return True
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -1,34 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.kms.kms_client import kms_client
def fixer(resource_id: str, region: str) -> bool:
class KmsCmkRotationEnabledFixer(AWSFixer):
"""
Enable CMK rotation. Requires the kms:EnableKeyRotation permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:EnableKeyRotation",
"Resource": "*"
}
]
}
Args:
resource_id (str): KMS CMK ID
region (str): AWS region
Returns:
bool: True if CMK rotation is enabled, False otherwise
Fixer to enable CMK rotation.
"""
try:
regional_client = kms_client.regional_clients[region]
regional_client.enable_key_rotation(KeyId=resource_id)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Enable CMK rotation.",
cost_impact=False,
cost_description=None,
service="kms",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:EnableKeyRotation",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable CMK rotation.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if CMK rotation is enabled, False otherwise
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = kms_client.regional_clients[region]
regional_client.enable_key_rotation(KeyId=resource_id)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,40 +1,66 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.neptune.neptune_client import neptune_client
def fixer(resource_id: str, region: str) -> bool:
class NeptuneClusterPublicSnapshotFixer(AWSFixer):
"""
Modify the attributes of a Neptune DB cluster snapshot to remove public access.
Specifically, this fixer removes the 'all' value from the 'restore' attribute to
prevent the snapshot from being publicly accessible. Requires the rds:ModifyDBClusterSnapshotAttribute permissions.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*"
}
]
}
Args:
resource_id (str): The DB cluster snapshot identifier.
region (str): AWS region where the snapshot exists.
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
Fixer to remove public access from Neptune DB cluster snapshots.
"""
try:
regional_client = neptune_client.regional_clients[region]
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
def __init__(self):
super().__init__(
description="Remove public access from Neptune DB cluster snapshots.",
cost_impact=False,
cost_description=None,
service="neptune",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from Neptune DB cluster snapshots.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if public access is removed, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = neptune_client.regional_clients[region]
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,43 +1,67 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.opensearch.opensearch_client import (
opensearch_client,
)
def fixer(resource_id: str, region: str) -> bool:
class OpensearchServiceDomainsNotPubliclyAccessibleFixer(AWSFixer):
"""
Modify the OpenSearch domain's resource-based policy to remove public access.
Specifically, this fixer update the domain config and add an empty policy to remove the old one.
Requires the es:UpdateDomainConfig permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "es:UpdateDomainConfig",
"Resource": "*"
}
]
}
Args:
resource_id (str): The OpenSearch domain name.
region (str): AWS region where the OpenSearch domain exists.
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
Fixer to remove public access from OpenSearch domains.
"""
try:
regional_client = opensearch_client.regional_clients[region]
regional_client.update_domain_config(
DomainName=resource_id,
AccessPolicies="",
def __init__(self):
super().__init__(
description="Remove public access from OpenSearch domains.",
cost_impact=False,
cost_description=None,
service="opensearch",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "es:UpdateDomainConfig",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from OpenSearch domains.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if public access is removed, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = opensearch_client.regional_clients[region]
regional_client.update_domain_config(
DomainName=resource_id,
AccessPolicies="",
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,40 +1,66 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.rds.rds_client import rds_client
def fixer(resource_id: str, region: str) -> bool:
class RdsInstanceNoPublicAccessFixer(AWSFixer):
"""
Modify the attributes of an RDS instance to disable public accessibility.
Specifically, this fixer sets the 'PubliclyAccessible' attribute to False
to prevent the RDS instance from being publicly accessible. Requires the rds:ModifyDBInstance permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBInstance",
"Resource": "*"
}
]
}
Args:
resource_id (str): The DB instance identifier.
region (str): AWS region where the DB instance exists.
Returns:
bool: True if the operation is successful (public access is disabled), False otherwise.
Fixer to disable public accessibility for RDS instances.
"""
try:
regional_client = rds_client.regional_clients[region]
regional_client.modify_db_instance(
DBInstanceIdentifier=resource_id,
PubliclyAccessible=False,
ApplyImmediately=True,
def __init__(self):
super().__init__(
description="Disable public accessibility for RDS instances.",
cost_impact=False,
cost_description=None,
service="rds",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBInstance",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Disable public accessibility for RDS instances.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if public access is disabled, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = rds_client.regional_clients[region]
regional_client.modify_db_instance(
DBInstanceIdentifier=resource_id,
PubliclyAccessible=False,
ApplyImmediately=True,
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,60 +1,86 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.rds.rds_client import rds_client
def fixer(resource_id: str, region: str) -> bool:
class RdsSnapshotsPublicAccessFixer(AWSFixer):
"""
Modify the attributes of an RDS DB snapshot or DB cluster snapshot to remove public access.
Specifically, this fixer removes the 'all' value from the 'restore' attribute to prevent the snapshot from being publicly accessible
for both DB snapshots and DB cluster snapshots. Requires the rds:ModifyDBSnapshotAttribute or rds:ModifyDBClusterSnapshotAttribute permissions.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBSnapshotAttribute",
"Resource": "*"
Fixer to remove public access from RDS DB snapshots and DB cluster snapshots.
"""
def __init__(self):
super().__init__(
description="Remove public access from RDS DB snapshots and DB cluster snapshots.",
cost_impact=False,
cost_description=None,
service="rds",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds:ModifyDBSnapshotAttribute",
"Resource": "*",
},
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*",
},
],
},
{
"Effect": "Allow",
"Action": "rds:ModifyDBClusterSnapshotAttribute",
"Resource": "*"
}
]
}
Args:
resource_id (str): The DB snapshot or DB cluster snapshot identifier.
region (str): AWS region where the snapshot exists.
Returns:
bool: True if the operation is successful (public access is removed), False otherwise.
"""
try:
regional_client = rds_client.regional_clients[region]
# Check if the resource is a DB Cluster Snapshot or a DB Instance Snapshot
try:
regional_client.describe_db_cluster_snapshots(
DBClusterSnapshotIdentifier=resource_id
)
# If the describe call is successful, it's a DB cluster snapshot
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
except regional_client.exceptions.DBClusterSnapshotNotFoundFault:
# If the DB cluster snapshot doesn't exist, it's an instance snapshot
regional_client.modify_db_snapshot_attribute(
DBSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from RDS DB snapshots and DB cluster snapshots.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if public access is removed, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = rds_client.regional_clients[region]
# Check if the resource is a DB Cluster Snapshot or a DB Instance Snapshot
try:
regional_client.describe_db_cluster_snapshots(
DBClusterSnapshotIdentifier=resource_id
)
# If the describe call is successful, it's a DB cluster snapshot
regional_client.modify_db_cluster_snapshot_attribute(
DBClusterSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
except regional_client.exceptions.DBClusterSnapshotNotFoundFault:
# If the DB cluster snapshot doesn't exist, it's an instance snapshot
regional_client.modify_db_snapshot_attribute(
DBSnapshotIdentifier=resource_id,
AttributeName="restore",
ValuesToRemove=["all"],
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,41 +1,67 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.s3.s3control_client import s3control_client
def fixer(resource_id: str) -> bool:
class S3AccountLevelPublicAccessBlocksFixer(AWSFixer):
"""
Enable S3 Block Public Access for the account. NOTE: By blocking all S3 public access you may break public S3 buckets.
Requires the s3:PutAccountPublicAccessBlock permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutAccountPublicAccessBlock",
"Resource": "*"
}
]
}
Args:
resource_id (str): The AWS account ID.
Returns:
bool: True if S3 Block Public Access is enabled, False otherwise
Fixer to enable S3 Block Public Access for the account.
"""
try:
s3control_client.client.put_public_access_block(
AccountId=resource_id,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
def __init__(self):
super().__init__(
description="Enable S3 Block Public Access for the account.",
cost_impact=False,
cost_description=None,
service="s3",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutAccountPublicAccessBlock",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable S3 Block Public Access for the account.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: resource_id (account id, if finding is not provided)
Returns:
bool: True if S3 Block Public Access is enabled, False otherwise
"""
try:
if finding:
resource_id = finding.resource_id
else:
resource_id = kwargs.get("resource_id")
if not resource_id:
raise ValueError("resource_id (account id) is required")
super().fix()
s3control_client.client.put_public_access_block(
AccountId=resource_id,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,38 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.s3.s3_client import s3_client
def fixer(resource_id: str, region: str) -> bool:
class S3BucketPolicyPublicWriteAccessFixer(AWSFixer):
"""
Modify the S3 bucket's policy to remove public access.
Specifically, this fixer delete the policy of the public bucket.
Requires the s3:DeleteBucketPolicy permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:DeleteBucketPolicy",
"Resource": "*"
}
]
}
Args:
resource_id (str): The S3 bucket name.
region (str): AWS region where the S3 bucket exists.
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
Fixer to remove public write access from S3 bucket policies.
"""
try:
regional_client = s3_client.regional_clients[region]
regional_client.delete_bucket_policy(Bucket=resource_id)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Remove public write access from S3 bucket policies.",
cost_impact=False,
cost_description=None,
service="s3",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:DeleteBucketPolicy",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public write access from S3 bucket policies.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the policy is removed, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = s3_client.regional_clients[region]
regional_client.delete_bucket_policy(Bucket=resource_id)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,46 +1,70 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.s3.s3_client import s3_client
def fixer(resource_id: str, region: str) -> bool:
class S3BucketPublicAccessFixer(AWSFixer):
"""
Modify the S3 bucket's public access settings to block all public access.
Specifically, this fixer configures the bucket's public access block settings to
prevent any public access (ACLs and policies). Requires the s3:PutBucketPublicAccessBlock
permission to modify the public access settings.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketPublicAccessBlock",
"Resource": "*"
}
]
}
Args:
resource_id (str): The S3 bucket name.
region (str): AWS region where the S3 bucket exists.
Returns:
bool: True if the operation is successful (public access is blocked),
False otherwise.
Fixer to block all public access to S3 buckets.
"""
try:
regional_client = s3_client.regional_clients[region]
regional_client.put_public_access_block(
Bucket=resource_id,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
def __init__(self):
super().__init__(
description="Block all public access to S3 buckets.",
cost_impact=False,
cost_description=None,
service="s3",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketPublicAccessBlock",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Block all public access to S3 buckets.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if public access is blocked, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = s3_client.regional_clients[region]
regional_client.put_public_access_block(
Bucket=resource_id,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,40 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.s3.s3_client import s3_client
def fixer(resource_id: str, region: str) -> bool:
class S3BucketPublicListAclFixer(AWSFixer):
"""
Modify the S3 bucket ACL to restrict public read access.
Specifically, this fixer sets the ACL of the bucket to 'private' to prevent
any public access to the S3 bucket.
Requires the s3:PutBucketAcl permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketAcl",
"Resource": "*"
}
]
}
Args:
resource_id (str): The S3 bucket name.
region (str): AWS region where the S3 bucket exists.
Returns:
bool: True if the operation is successful (bucket access is updated), False otherwise.
Fixer to restrict public read access by setting the S3 bucket ACL to 'private'.
"""
try:
regional_client = s3_client.regional_clients[region]
regional_client.put_bucket_acl(Bucket=resource_id, ACL="private")
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Restrict public read access by setting the S3 bucket ACL to 'private'.",
cost_impact=False,
cost_description=None,
service="s3",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketAcl",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Restrict public read access by setting the S3 bucket ACL to 'private'.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the bucket ACL is set to private, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = s3_client.regional_clients[region]
regional_client.put_bucket_acl(Bucket=resource_id, ACL="private")
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,36 +1,62 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.s3.s3_client import s3_client
def fixer(resource_id: str, region: str) -> bool:
class S3BucketPublicWriteAclFixer(AWSFixer):
"""
Modify the S3 bucket ACL to restrict public write access.
Specifically, this fixer sets the ACL of the bucket to 'private' to prevent
public write access to the S3 bucket. Requires the s3:PutBucketAcl permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketAcl",
"Resource": "*"
}
]
}
Args:
resource_id (str): The S3 bucket id.
region (str): AWS region where the S3 bucket exists.
Returns:
bool: True if the operation is successful (bucket access is updated), False otherwise.
Fixer to restrict public write access by setting the S3 bucket ACL to 'private'.
"""
try:
regional_client = s3_client.regional_clients[region]
regional_client.put_bucket_acl(Bucket=resource_id, ACL="private")
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
def __init__(self):
super().__init__(
description="Restrict public write access by setting the S3 bucket ACL to 'private'.",
cost_impact=False,
cost_description=None,
service="s3",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutBucketAcl",
"Resource": "*",
}
],
},
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Restrict public write access by setting the S3 bucket ACL to 'private'.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the bucket ACL is set to private, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
regional_client = s3_client.regional_clients[region]
regional_client.put_bucket_acl(Bucket=resource_id, ACL="private")
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,39 +1,66 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.securityhub.securityhub_client import (
securityhub_client,
)
def fixer(region):
class SecurityhubEnabledFixer(AWSFixer):
"""
Enable Security Hub in a region. Requires the securityhub:EnableSecurityHub permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "securityhub:EnableSecurityHub",
"Resource": "*"
}
]
}
Args:
region (str): AWS region
Returns:
bool: True if Security Hub is enabled, False otherwise
Fixer to enable Security Hub in a region.
"""
try:
regional_client = securityhub_client.regional_clients[region]
regional_client.enable_security_hub(
EnableDefaultStandards=securityhub_client.fixer_config.get(
"securityhub_enabled", {}
).get("EnableDefaultStandards", True)
def __init__(self):
super().__init__(
description="Enable Security Hub in a region.",
cost_impact=True,
cost_description="Enabling Security Hub incurs costs for findings ingestion, analysis, and resource coverage. Charges apply per finding and per resource. See AWS Security Hub pricing.",
service="securityhub",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "securityhub:EnableSecurityHub",
"Resource": "*",
}
],
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Enable Security Hub in a region.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region (if finding is not provided)
Returns:
bool: True if Security Hub is enabled, False otherwise
"""
try:
if finding:
region = finding.region
else:
region = kwargs.get("region")
if not region:
raise ValueError("region is required")
super().fix(region=region)
regional_client = securityhub_client.regional_clients[region]
regional_client.enable_security_hub(
EnableDefaultStandards=securityhub_client.fixer_config.get(
"securityhub_enabled", {}
).get("EnableDefaultStandards", True)
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -1,64 +1,85 @@
import json
from typing import Optional
from prowler.lib.check.models import Check_Report_AWS
from prowler.lib.logger import logger
from prowler.providers.aws.lib.fix.fixer import AWSFixer
from prowler.providers.aws.services.sqs.sqs_client import sqs_client
def fixer(resource_id: str, region: str) -> bool:
class SqsQueuesNotPubliclyAccessibleFixer(AWSFixer):
"""
Modify the SQS queue's resource-based policy to remove public access and replace with trusted account access.
Specifically, this fixer checks if any statement has a public Principal (e.g., "*" or "CanonicalUser")
and replaces it with the ARN of the trusted AWS account.
Requires the sqs:SetQueueAttributes permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sqs:SetQueueAttributes",
"Resource": "*"
Fixer to remove public access from SQS queue policies and replace with trusted account access.
"""
def __init__(self):
super().__init__(
description="Remove public access from SQS queue policies and replace with trusted account access.",
cost_impact=False,
cost_description=None,
service="sqs",
iam_policy_required={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sqs:SetQueueAttributes",
"Resource": "*",
}
],
},
)
def fix(self, finding: Optional[Check_Report_AWS] = None, **kwargs) -> bool:
"""
Remove public access from SQS queue policies and replace with trusted account access.
Args:
finding (Optional[Check_Report_AWS]): Finding to fix
**kwargs: region, resource_id (if finding is not provided)
Returns:
bool: True if the policy is updated, False otherwise.
"""
try:
if finding:
region = finding.region
resource_id = finding.resource_id
else:
region = kwargs.get("region")
resource_id = kwargs.get("resource_id")
if not region or not resource_id:
raise ValueError("region and resource_id are required")
super().fix(region=region, resource_id=resource_id)
account_id = sqs_client.audited_account
audited_partition = sqs_client.audited_partition
regional_client = sqs_client.regional_clients[region]
queue_name = resource_id.split("/")[-1]
trusted_policy = {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProwlerFixerStatement",
"Effect": "Allow",
"Principal": {
"AWS": account_id,
},
"Action": "sqs:*",
"Resource": f"arn:{audited_partition}:sqs:{region}:{account_id}:{queue_name}",
}
],
}
]
}
Args:
resource_id (str): The SQS queue name or ARN.
region (str): AWS region where the SQS queue exists.
Returns:
bool: True if the operation is successful (policy updated), False otherwise.
"""
try:
account_id = sqs_client.audited_account
audited_partition = sqs_client.audited_partition
regional_client = sqs_client.regional_clients[region]
queue_name = resource_id.split("/")[-1]
trusted_policy = {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProwlerFixerStatement",
"Effect": "Allow",
"Principal": {
"AWS": account_id,
},
"Action": "sqs:*",
"Resource": f"arn:{audited_partition}:sqs:{region}:{account_id}:{queue_name}",
}
],
}
regional_client.set_queue_attributes(
QueueUrl=resource_id,
Attributes={"Policy": json.dumps(trusted_policy)},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
regional_client.set_queue_attributes(
QueueUrl=resource_id,
Attributes={"Policy": json.dumps(trusted_policy)},
)
except Exception as error:
logger.error(
f"{region if 'region' in locals() else 'unknown'} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True

View File

@@ -0,0 +1,97 @@
from typing import Dict, Optional
from colorama import Style
from prowler.config.config import orange_color
from prowler.lib.check.models import Check_Report_Azure
from prowler.lib.fix.fixer import Fixer
from prowler.lib.logger import logger
class AzureFixer(Fixer):
"""Azure specific fixer implementation"""
def __init__(
self,
description: str,
cost_impact: bool = False,
cost_description: Optional[str] = None,
service: str = "",
permissions_required: Optional[Dict] = None,
):
super().__init__(description, cost_impact, cost_description)
self.service = service
self.permissions_required = permissions_required or {}
def _get_fixer_info(self):
"""Each fixer must define its metadata"""
fixer_info = super()._get_fixer_info()
fixer_info["service"] = self.service
fixer_info["permissions_required"] = self.permissions_required
return fixer_info
def fix(self, finding: Optional[Check_Report_Azure] = None, **kwargs) -> bool:
"""
Azure specific method to execute the fixer.
This method handles the printing of fixing status messages.
Args:
finding (Optional[Check_Report_Azure]): Finding to fix
**kwargs: Additional Azure-specific arguments (subscription_id, resource_id, resource_group)
Returns:
bool: True if fixing was successful, False otherwise
"""
try:
# Get values either from finding or kwargs
subscription_id = None
resource_id = None
resource_group = None
if finding:
subscription_id = (
finding.subscription if hasattr(finding, "subscription") else None
)
resource_id = (
finding.resource_id if hasattr(finding, "resource_id") else None
)
resource_group = (
finding.resource.get("resource_group_name")
if hasattr(finding.resource, "resource_group_name")
else None
)
else:
subscription_id = kwargs.get("subscription_id")
resource_id = kwargs.get("resource_id")
resource_group = kwargs.get("resource_group")
# Print the appropriate message based on available information
if subscription_id and resource_id and resource_group:
print(
f"\t{orange_color}FIXING Resource {resource_id} in Resource Group {resource_group} (Subscription: {subscription_id})...{Style.RESET_ALL}"
)
elif subscription_id and resource_id:
print(
f"\t{orange_color}FIXING Resource {resource_id} (Subscription: {subscription_id})...{Style.RESET_ALL}"
)
elif subscription_id:
print(
f"\t{orange_color}FIXING Subscription {subscription_id}...{Style.RESET_ALL}"
)
elif resource_id:
print(
f"\t{orange_color}FIXING Resource {resource_id}...{Style.RESET_ALL}"
)
else:
logger.error(
"Either finding or required kwargs (subscription_id, resource_id, resource_group) must be provided"
)
return False
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -0,0 +1,75 @@
from typing import Optional
from azure.mgmt.web.models import SiteConfigResource
from prowler.lib.check.models import Check_Report_Azure
from prowler.providers.azure.lib.fix.fixer import AzureFixer
from prowler.providers.azure.services.app.app_client import app_client
class AppFunctionFtpsDeploymentDisabledFixer(AzureFixer):
"""
This class handles the remediation of the app_function_ftps_deployment_disabled check.
It disables FTP/FTPS deployments for Azure Functions to prevent unauthorized access.
"""
def __init__(self):
super().__init__(
description="Disable FTP/FTPS deployments for Azure Functions",
service="app",
cost_impact=False,
cost_description=None,
permissions_required={
"Microsoft.Web/sites/config/write": "Write access to the site configuration",
},
)
def fix(self, finding: Optional[Check_Report_Azure] = None, **kwargs) -> bool:
"""
Fix the failed check by disabling FTP/FTPS deployments for the Azure Function.
Args:
finding (Check_Report_Azure): Finding to fix
**kwargs: Additional Azure-specific arguments (subscription_id, resource_id, resource_group)
Returns:
bool: True if FTP/FTPS is disabled, False otherwise
"""
try:
if finding:
resource_group = finding.resource.get("resource_group_name")
resource_id = finding.resource_name
suscription_id = finding.subscription
else:
resource_group = kwargs.get("resource_group")
resource_id = kwargs.get("resource_id")
suscription_id = kwargs.get("subscription_id")
if not resource_group or not resource_id or not suscription_id:
raise ValueError(
"Resource group, app name and subscription name are required"
)
super().fix(
resource_group=resource_group,
resource_id=resource_id,
suscription_id=suscription_id,
)
client = app_client.clients[suscription_id]
site_config = SiteConfigResource(ftps_state="Disabled")
client.web_apps.update_configuration(
resource_group_name=resource_group,
name=resource_id,
site_config=site_config,
)
return True
except Exception as error:
self.logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -170,6 +170,7 @@ class App(AzureService):
ftps_state=getattr(
function_config, "ftps_state", None
),
resource_group_name=function.resource_group,
)
}
)
@@ -293,3 +294,4 @@ class FunctionApp:
public_access: bool
vnet_subnet_id: str
ftps_state: Optional[str]
resource_group_name: str

View File

@@ -0,0 +1,97 @@
from typing import Dict, Optional
from prowler.lib.check.models import Check_Report_GCP
from prowler.lib.fix.fixer import Fixer
from prowler.lib.logger import logger
from prowler.providers.gcp.gcp_provider import GcpProvider
class GCPFixer(Fixer):
"""GCP specific fixer implementation"""
def __init__(
self,
description: str,
cost_impact: bool = False,
cost_description: Optional[str] = None,
service: str = "",
iam_policy_required: Optional[Dict] = None,
):
"""
Initialize GCP fixer with metadata.
Args:
description (str): Description of the fixer
cost_impact (bool): Whether the fixer has a cost impact
cost_description (Optional[str]): Description of the cost impact
service (str): GCP service name
iam_policy_required (Optional[Dict]): Required IAM policy for the fixer
"""
super().__init__(description, cost_impact, cost_description)
self.service = service
self.iam_policy_required = iam_policy_required or {}
self._provider = None
@property
def provider(self) -> GcpProvider:
"""Get the GCP provider instance"""
if not self._provider:
self._provider = GcpProvider()
return self._provider
def _get_fixer_info(self) -> Dict:
"""Get fixer metadata"""
info = super()._get_fixer_info()
info["service"] = self.service
info["iam_policy_required"] = self.iam_policy_required
info["provider"] = "gcp"
return info
def fix(self, finding: Optional[Check_Report_GCP] = None, **kwargs) -> bool:
"""
GCP specific method to execute the fixer.
This method handles the printing of fixing status messages.
Args:
finding (Optional[Check_Report_GCP]): Finding to fix
**kwargs: Additional GCP-specific arguments (project_id, resource_id)
Returns:
bool: True if fixing was successful, False otherwise
"""
try:
# Get values either from finding or kwargs
project_id = None
resource_id = None
if finding:
project_id = (
finding.project_id if hasattr(finding, "project_id") else None
)
resource_id = (
finding.resource_id if hasattr(finding, "resource_id") else None
)
else:
project_id = kwargs.get("project_id")
resource_id = kwargs.get("resource_id")
# Print the appropriate message based on available information
if project_id and resource_id:
print(f"\tFIXING {resource_id} in project {project_id}...")
elif project_id:
print(f"\tFIXING project {project_id}...")
elif resource_id:
print(f"\tFIXING Resource {resource_id}...")
else:
logger.error(
"Either finding or required kwargs (project_id, resource_id) must be provided"
)
return False
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -0,0 +1,63 @@
from typing import Optional
from prowler.lib.check.models import Check_Report_GCP
from prowler.lib.logger import logger
from prowler.providers.gcp.lib.fix.fixer import GCPFixer
from prowler.providers.gcp.services.compute.compute_client import compute_client
class ComputeProjectOsLoginEnabledFixer(GCPFixer):
"""
Fixer for enabling OS Login at the project level.
This fixer enables the OS Login feature which provides centralized and automated SSH key pair management.
"""
def __init__(self):
"""
Initialize Compute Engine fixer.
"""
super().__init__(
description="Enable OS Login at the project level",
cost_impact=False,
cost_description=None,
service="compute",
iam_policy_required={
"roles": ["roles/compute.admin"],
},
)
def fix(self, finding: Optional[Check_Report_GCP] = None, **kwargs) -> bool:
"""
Enable OS Login at the project level.
Args:
finding (Optional[Check_Report_GCP]): Finding to fix
**kwargs: Additional arguments (project_id is required if finding is not provided)
Returns:
bool: True if the operation is successful (OS Login is enabled), False otherwise
"""
try:
# Get project_id either from finding or kwargs
if finding:
project_id = finding.project_id
else:
project_id = kwargs.get("project_id")
if not project_id:
raise ValueError("project_id is required")
# Enable OS Login
request = compute_client.client.projects().setCommonInstanceMetadata(
project=project_id,
body={"items": [{"key": "enable-oslogin", "value": "TRUE"}]},
)
request.execute()
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -0,0 +1,68 @@
from typing import Optional
from colorama import Style
from prowler.config.config import orange_color
from prowler.lib.check.models import CheckReportM365
from prowler.lib.fix.fixer import Fixer
from prowler.lib.logger import logger
class M365Fixer(Fixer):
"""M365 specific fixer implementation"""
def __init__(
self,
description: str,
cost_impact: bool = False,
cost_description: Optional[str] = None,
service: str = "",
):
super().__init__(description, cost_impact, cost_description)
self.service = service
def _get_fixer_info(self):
"""Each fixer must define its metadata"""
fixer_info = super()._get_fixer_info()
fixer_info["service"] = self.service
return fixer_info
def fix(self, finding: Optional[CheckReportM365] = None, **kwargs) -> bool:
"""
M365 specific method to execute the fixer.
This method handles the printing of fixing status messages.
Args:
finding (Optional[CheckReportM365]): Finding to fix
**kwargs: Additional M365-specific arguments (resource_id)
Returns:
bool: True if fixing was successful, False otherwise
"""
try:
# Get values either from finding or kwargs
resource_id = None
if finding:
resource_id = (
finding.resource_id if hasattr(finding, "resource_id") else None
)
elif kwargs.get("resource_id"):
resource_id = kwargs.get("resource_id")
# Print the appropriate message based on available information
if resource_id:
print(
f"\t{orange_color}FIXING Resource {resource_id}...{Style.RESET_ALL}"
)
else:
# If no resource_id is provided, we'll still try to proceed
print(f"\t{orange_color}FIXING...{Style.RESET_ALL}")
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False

View File

@@ -869,6 +869,20 @@ class M365PowerShell(PowerShellSession):
"""
return self.execute("Get-TransportConfig | ConvertTo-Json", json_parse=True)
def set_audit_log_config(self):
"""
Set Purview Admin Audit Log Settings.
Sets the audit log configuration settings for Microsoft Purview.
Args:
enabled (bool): Whether to enable or disable the audit log.
"""
return self.execute(
"Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true"
)
def get_sharing_policy(self) -> dict:
"""
Get Exchange Online Sharing Policy.

View File

@@ -219,6 +219,9 @@ class M365Provider(Provider):
# Fixer Config
self._fixer_config = fixer_config
# Output Options
self._output_options = None
# Mutelist
if mutelist_content:
self._mutelist = M365Mutelist(
@@ -1136,3 +1139,10 @@ class M365Provider(Provider):
except Exception as error:
# Generic exception handling for unexpected errors
raise RuntimeError(f"An unexpected error occurred: {str(error)}")
@property
def output_options(self):
return self._output_options
def set_output_options(self, output_options):
self._output_options = output_options

View File

@@ -56,3 +56,6 @@ class M365OutputOptions(ProviderOutputOptions):
)
else:
self.output_filename = arguments.output_filename
# Add fixer mode to the output options
self.fixer = arguments.fixer if hasattr(arguments, "fixer") else False

View File

@@ -0,0 +1,49 @@
from typing import Optional
from prowler.lib.check.models import CheckReportM365
from prowler.lib.logger import logger
from prowler.providers.m365.lib.fix.fixer import M365Fixer
from prowler.providers.m365.services.purview.purview_client import purview_client
class PurviewAuditLogSearchEnabledFixer(M365Fixer):
"""
Fixer for Purview audit log search.
This fixer enables the audit log search using PowerShell.
"""
def __init__(self):
"""
Initialize Purview audit log search fixer.
"""
super().__init__(
description="Enable Purview audit log search",
cost_impact=False,
cost_description=None,
service="purview",
)
def fix(self, finding: Optional[CheckReportM365] = None, **kwargs) -> bool:
"""
Enable Purview audit log search using PowerShell.
This fixer executes the Set-AdminAuditLogConfig cmdlet to enable the audit log search.
Args:
finding (Optional[CheckReportM365]): Finding to fix
**kwargs: Additional arguments
Returns:
bool: True if the operation is successful (audit log search is enabled), False otherwise
"""
try:
super().fix()
purview_client.powershell.set_audit_log_config()
purview_client.powershell.close()
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
purview_client.powershell.close()
return False

View File

@@ -13,7 +13,8 @@ class Purview(M365Service):
if self.powershell:
self.powershell.connect_exchange_online()
self.audit_log_config = self._get_audit_log_config()
self.powershell.close()
if not provider.output_options.fixer:
self.powershell.close()
def _get_audit_log_config(self):
logger.info("M365 - Getting Admin Audit Log settings...")

207
tests/lib/fix/fixer_test.py Normal file
View File

@@ -0,0 +1,207 @@
import json
from unittest.mock import MagicMock, patch
import pytest
from prowler.lib.check.models import (
Check_Report,
CheckMetadata,
Code,
Recommendation,
Remediation,
)
from prowler.lib.fix.fixer import Fixer
def get_mock_metadata(
provider="aws", check_id="test_check", service_name="testservice"
):
return CheckMetadata(
Provider=provider,
CheckID=check_id,
CheckTitle="Test Check",
CheckType=["type1"],
CheckAliases=[],
ServiceName=service_name,
SubServiceName="",
ResourceIdTemplate="",
Severity="low",
ResourceType="resource",
Description="desc",
Risk="risk",
RelatedUrl="url",
Remediation=Remediation(
Code=Code(NativeIaC="", Terraform="", CLI="", Other=""),
Recommendation=Recommendation(Text="", Url=""),
),
Categories=["cat1"],
DependsOn=[],
RelatedTo=[],
Notes="",
Compliance=[],
)
def build_metadata(provider="aws", check_id="test_check", service_name="testservice"):
return CheckMetadata(
Provider=provider,
CheckID=check_id,
CheckTitle="Test Check",
CheckType=["type1"],
CheckAliases=[],
ServiceName=service_name,
SubServiceName="",
ResourceIdTemplate="",
Severity="low",
ResourceType="resource",
Description="desc",
Risk="risk",
RelatedUrl="url",
Remediation=Remediation(
Code=Code(NativeIaC="", Terraform="", CLI="", Other=""),
Recommendation=Recommendation(Text="", Url=""),
),
Categories=["cat1"],
DependsOn=[],
RelatedTo=[],
Notes="",
Compliance=[],
)
def build_finding(
status="FAIL", provider="aws", check_id="test_check", service_name="testservice"
):
metadata = build_metadata(provider, check_id, service_name)
resource = MagicMock()
finding = Check_Report(json.dumps(metadata.dict()), resource)
finding.status = status
return finding
class DummyFixer(Fixer):
def fix(self, finding=None, **kwargs):
return True
class TestFixer:
def test_get_fixer_info(self):
fixer = DummyFixer(
description="desc", cost_impact=True, cost_description="cost"
)
info = fixer._get_fixer_info()
assert info == {
"description": "desc",
"cost_impact": True,
"cost_description": "cost",
}
def test_client_property(self):
fixer = DummyFixer(description="desc")
assert fixer.client is None
@pytest.mark.parametrize(
"check_id,provider,service_name,expected_class",
[
(None, "aws", "testservice", None),
("test_check", None, "testservice", None),
("nonexistent_check", "aws", "testservice", None),
],
)
def test_get_fixer_for_finding_edge(
self, check_id, provider, service_name, expected_class
):
finding = MagicMock()
finding.check_metadata.CheckID = check_id
finding.check_metadata.Provider = provider
finding.check_metadata.ServiceName = service_name
with patch("prowler.lib.fix.fixer.logger"):
fixer = Fixer.get_fixer_for_finding(finding)
assert fixer is expected_class
def test_get_fixer_for_finding_importerror_print(self):
finding = MagicMock()
finding.check_metadata.CheckID = "nonexistent_check"
finding.check_metadata.Provider = "aws"
finding.check_metadata.ServiceName = "testservice"
with patch("builtins.print") as mock_print:
fixer = Fixer.get_fixer_for_finding(finding)
assert fixer is None
assert mock_print.called
def test_run_fixer_single_and_multiple(self):
finding = build_finding(status="FAIL")
with patch.object(Fixer, "run_individual_fixer", return_value=1) as mock_run:
assert Fixer.run_fixer(finding) == 1
assert mock_run.called
finding.status = "PASS"
assert Fixer.run_fixer(finding) == 0
finding1 = build_finding(status="FAIL")
finding2 = build_finding(status="FAIL")
with patch.object(Fixer, "run_individual_fixer", return_value=2) as mock_run:
assert Fixer.run_fixer([finding1, finding2]) == 2
assert mock_run.called
def test_run_fixer_grouping(self):
finding1 = build_finding(status="FAIL", check_id="check1")
finding2 = build_finding(status="FAIL", check_id="check1")
finding3 = build_finding(status="FAIL", check_id="check2")
calls = {}
def fake_run_individual_fixer(check_id, findings):
calls[check_id] = len(findings)
return len(findings)
with patch.object(
Fixer, "run_individual_fixer", side_effect=fake_run_individual_fixer
):
total = Fixer.run_fixer([finding1, finding2, finding3])
assert total == 3
assert calls == {"check1": 2, "check2": 1}
def test_run_fixer_exception(self):
finding = build_finding(status="FAIL")
with patch.object(Fixer, "run_individual_fixer", side_effect=Exception("fail")):
with patch("prowler.lib.fix.fixer.logger") as mock_logger:
assert Fixer.run_fixer(finding) == 0
assert mock_logger.error.called
def test_run_individual_fixer_success(self):
finding = build_finding(status="FAIL")
with (
patch.object(Fixer, "get_fixer_for_finding") as mock_factory,
patch("builtins.print") as mock_print,
):
fixer = DummyFixer(description="desc")
mock_factory.return_value = fixer
with patch.object(fixer, "fix", return_value=True):
total = Fixer.run_individual_fixer("test_check", [finding])
assert total == 1
assert mock_print.call_count > 0
def test_run_individual_fixer_no_fixer(self):
finding = build_finding(status="FAIL")
with patch.object(Fixer, "get_fixer_for_finding", return_value=None):
assert Fixer.run_individual_fixer("test_check", [finding]) == 0
def test_run_individual_fixer_fix_error(self):
finding = build_finding(status="FAIL")
with (
patch.object(Fixer, "get_fixer_for_finding") as mock_factory,
patch("builtins.print") as mock_print,
):
fixer = DummyFixer(description="desc")
mock_factory.return_value = fixer
with patch.object(fixer, "fix", return_value=False):
total = Fixer.run_individual_fixer("test_check", [finding])
assert total == 0
assert mock_print.call_count > 0
def test_run_individual_fixer_exception(self):
finding = build_finding(status="FAIL")
with patch.object(
Fixer, "get_fixer_for_finding", side_effect=Exception("fail")
):
with patch("prowler.lib.fix.fixer.logger") as mock_logger:
assert Fixer.run_individual_fixer("test_check", [finding]) == 0
assert mock_logger.error.called

View File

@@ -0,0 +1,104 @@
import json
from unittest.mock import MagicMock, patch
from prowler.lib.check.models import (
Check_Report_AWS,
CheckMetadata,
Code,
Recommendation,
Remediation,
)
from prowler.providers.aws.lib.fix.fixer import AWSFixer
def get_mock_aws_finding():
metadata = CheckMetadata(
Provider="aws",
CheckID="test_check",
CheckTitle="Test Check",
CheckType=["type1"],
CheckAliases=[],
ServiceName="testservice",
SubServiceName="",
ResourceIdTemplate="",
Severity="low",
ResourceType="resource",
Description="desc",
Risk="risk",
RelatedUrl="url",
Remediation=Remediation(
Code=Code(NativeIaC="", Terraform="", CLI="", Other=""),
Recommendation=Recommendation(Text="", Url=""),
),
Categories=["cat1"],
DependsOn=[],
RelatedTo=[],
Notes="",
Compliance=[],
)
resource = MagicMock()
resource.id = "res_id"
resource.arn = "arn:aws:test"
resource.region = "eu-west-1"
return Check_Report_AWS(json.dumps(metadata.dict()), resource)
class TestAWSFixer:
def test_fix_success(self):
finding = get_mock_aws_finding()
finding.status = "FAIL"
with patch("prowler.providers.aws.lib.fix.fixer.AWSFixer.client"):
fixer = AWSFixer(description="desc", service="ec2")
assert fixer.fix(finding=finding)
def test_fix_failure(self, caplog):
fixer = AWSFixer(description="desc", service="ec2")
with patch("prowler.providers.aws.lib.fix.fixer.logger") as mock_logger:
with caplog.at_level("ERROR"):
result = fixer.fix(finding=None)
assert result is False
assert mock_logger.error.called
def test_get_fixer_info(self):
fixer = AWSFixer(
description="desc",
service="ec2",
cost_impact=True,
cost_description="cost",
iam_policy_required={"Action": ["ec2:DescribeInstances"]},
)
info = fixer._get_fixer_info()
assert info["description"] == "desc"
assert info["cost_impact"] is True
assert info["cost_description"] == "cost"
assert info["service"] == "ec2"
assert info["iam_policy_required"] == {"Action": ["ec2:DescribeInstances"]}
def test_fix_prints(self):
fixer = AWSFixer(description="desc", service="ec2")
finding = get_mock_aws_finding()
finding.region = "eu-west-1"
finding.resource_id = "res_id"
finding.resource_arn = "arn:aws:test"
with (
patch("builtins.print") as mock_print,
patch("prowler.providers.aws.lib.fix.fixer.logger") as mock_logger,
):
result = fixer.fix(finding=finding)
if (
finding.region
or finding.resource_id
or getattr(finding, "resource_arn", None)
):
assert result is True
assert mock_print.called
else:
assert result is False
assert mock_logger.error.called
def test_fix_exception(self):
fixer = AWSFixer(description="desc", service="ec2")
with patch("prowler.providers.aws.lib.fix.fixer.logger") as mock_logger:
result = fixer.fix(finding=None)
assert result is False
assert mock_logger.error.called

View File

@@ -3,7 +3,7 @@ from unittest import mock
from tests.providers.aws.utils import AWS_ACCOUNT_ARN, AWS_REGION_EU_WEST_1
class Test_accessanalyzer_enabled_fixer:
class TestAccessAnalyzerEnabledFixer:
def test_accessanalyzer_enabled_fixer(self):
regional_client = mock.MagicMock()
accessanalyzer_client = mock.MagicMock()
@@ -26,7 +26,7 @@ class Test_accessanalyzer_enabled_fixer:
):
# Test Check
from prowler.providers.aws.services.accessanalyzer.accessanalyzer_enabled.accessanalyzer_enabled_fixer import (
fixer,
AccessAnalyzerEnabledFixer,
)
assert fixer(AWS_REGION_EU_WEST_1)
assert AccessAnalyzerEnabledFixer().fix(region=AWS_REGION_EU_WEST_1)

View File

@@ -11,7 +11,7 @@ from tests.providers.aws.utils import (
)
class Test_awslambda_function_not_publicly_accessible_fixer:
class TestLambdaFunctionNotPubliclyAccessibleFixer:
@mock_aws
def test_function_public(self):
# Create the mock IAM role
@@ -71,12 +71,12 @@ class Test_awslambda_function_not_publicly_accessible_fixer:
new=Lambda(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import (
fixer,
LambdaFunctionNotPubliclyAccessibleFixer,
)
assert fixer(function_name, AWS_REGION_EU_WEST_1)
fixer = LambdaFunctionNotPubliclyAccessibleFixer()
assert fixer.fix(region=AWS_REGION_EU_WEST_1, resource_id=function_name)
@mock_aws
def test_function_public_with_source_account(self):
@@ -139,12 +139,12 @@ class Test_awslambda_function_not_publicly_accessible_fixer:
new=Lambda(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import (
fixer,
LambdaFunctionNotPubliclyAccessibleFixer,
)
assert fixer(function_name, AWS_REGION_EU_WEST_1)
fixer = LambdaFunctionNotPubliclyAccessibleFixer()
assert fixer.fix(region=AWS_REGION_EU_WEST_1, resource_id=function_name)
@mock_aws
def test_function_not_public(self):
@@ -206,12 +206,12 @@ class Test_awslambda_function_not_publicly_accessible_fixer:
new=Lambda(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import (
fixer,
LambdaFunctionNotPubliclyAccessibleFixer,
)
assert fixer(function_name, AWS_REGION_EU_WEST_1)
fixer = LambdaFunctionNotPubliclyAccessibleFixer()
assert fixer.fix(region=AWS_REGION_EU_WEST_1, resource_id=function_name)
@mock_aws
def test_function_public_error(self):
@@ -272,9 +272,9 @@ class Test_awslambda_function_not_publicly_accessible_fixer:
new=Lambda(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import (
fixer,
LambdaFunctionNotPubliclyAccessibleFixer,
)
assert not fixer("non-exsting", AWS_REGION_EU_WEST_1)
fixer = LambdaFunctionNotPubliclyAccessibleFixer()
assert not fixer.fix(region=AWS_REGION_EU_WEST_1, resource_id="non-exsting")

View File

@@ -28,7 +28,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer:
class TestCloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer:
@mock_aws
def test_trail_bucket_public_acl(self):
aws_provider = set_mocked_aws_provider(
@@ -81,12 +81,12 @@ class Test_cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer:
new=S3(aws_provider),
),
):
# Test Check
from prowler.providers.aws.services.cloudtrail.cloudtrail_logs_s3_bucket_is_not_publicly_accessible.cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer import (
fixer,
CloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer,
)
assert fixer(trail_name_us, AWS_REGION_US_EAST_1)
fixer = CloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1, resource_id=trail_name_us)
@mock_aws
def test_trail_bucket_public_acl_error(self):
@@ -145,9 +145,11 @@ class Test_cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer:
new=S3(aws_provider),
),
):
# Test Check
from prowler.providers.aws.services.cloudtrail.cloudtrail_logs_s3_bucket_is_not_publicly_accessible.cloudtrail_logs_s3_bucket_is_not_publicly_accessible_fixer import (
fixer,
CloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer,
)
assert not fixer(trail_name_us, AWS_REGION_US_EAST_1)
fixer = CloudtrailLogsS3BucketIsNotPubliclyAccessibleFixer()
assert not fixer.fix(
region=AWS_REGION_US_EAST_1, resource_id=trail_name_us
)

View File

@@ -6,7 +6,7 @@ from moto import mock_aws
from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider
class Test_cloudtrail_multi_region_enabled_fixer:
class TestCloudtrailMultiRegionEnabledFixer:
@mock_aws
def test_cloudtrail_multi_region_enabled_fixer(self):
from prowler.providers.aws.services.cloudtrail.cloudtrail_service import (
@@ -36,9 +36,9 @@ class Test_cloudtrail_multi_region_enabled_fixer:
"prowler.providers.aws.services.cloudtrail.cloudtrail_multi_region_enabled.cloudtrail_multi_region_enabled_fixer.cloudtrail_client",
new=Cloudtrail(aws_provider),
):
# Test Check
from prowler.providers.aws.services.cloudtrail.cloudtrail_multi_region_enabled.cloudtrail_multi_region_enabled_fixer import (
fixer,
CloudtrailMultiRegionEnabledFixer,
)
assert fixer(AWS_REGION_US_EAST_1)
fixer = CloudtrailMultiRegionEnabledFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1)

View File

@@ -38,7 +38,7 @@ def mock_make_api_call_codeartifact_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_codeartifact_packages_external_public_publishing_disabled_fixer:
class TestCodeartifactPackagesExternalPublicPublishingDisabledFixer:
@mock_aws
def test_repository_package_public_publishing_origin_internal(self):
with mock.patch(
@@ -57,12 +57,14 @@ class Test_codeartifact_packages_external_public_publishing_disabled_fixer:
new=CodeArtifact(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import (
fixer,
CodeartifactPackagesExternalPublicPublishingDisabledFixer,
)
assert fixer("test/test-package", AWS_REGION_EU_WEST_1)
fixer = CodeartifactPackagesExternalPublicPublishingDisabledFixer()
assert fixer.fix(
region=AWS_REGION_EU_WEST_1, resource_id="test/test-package"
)
@mock_aws
def test_repository_package_public_publishing_origin_internal_error(self):
@@ -70,7 +72,6 @@ class Test_codeartifact_packages_external_public_publishing_disabled_fixer:
"botocore.client.BaseClient._make_api_call",
new=mock_make_api_call_codeartifact_error,
):
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
with (
@@ -83,9 +84,11 @@ class Test_codeartifact_packages_external_public_publishing_disabled_fixer:
new=CodeArtifact(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import (
fixer,
CodeartifactPackagesExternalPublicPublishingDisabledFixer,
)
assert not fixer("non-existing-package", AWS_REGION_EU_WEST_1)
fixer = CodeartifactPackagesExternalPublicPublishingDisabledFixer()
assert not fixer.fix(
region=AWS_REGION_EU_WEST_1, resource_id="non-existing-package"
)

View File

@@ -39,7 +39,7 @@ def mock_make_api_call_public_snapshot_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_documentdb_cluster_public_snapshot_fixer:
class TestDocumentdbClusterPublicSnapshotFixer:
@mock_aws
def test_documentdb_cluster_public_snapshot_fixer(self):
with mock.patch(
@@ -63,10 +63,13 @@ class Test_documentdb_cluster_public_snapshot_fixer:
),
):
from prowler.providers.aws.services.documentdb.documentdb_cluster_public_snapshot.documentdb_cluster_public_snapshot_fixer import (
fixer,
DocumentdbClusterPublicSnapshotFixer,
)
assert fixer(resource_id="test-snapshot", region=AWS_REGION_EU_WEST_1)
fixer = DocumentdbClusterPublicSnapshotFixer()
assert fixer.fix(
region=AWS_REGION_EU_WEST_1, resource_id="test-snapshot"
)
@mock_aws
def test_documentdb_cluster_public_snapshot_fixer_error(self):
@@ -91,9 +94,10 @@ class Test_documentdb_cluster_public_snapshot_fixer:
),
):
from prowler.providers.aws.services.documentdb.documentdb_cluster_public_snapshot.documentdb_cluster_public_snapshot_fixer import (
fixer,
DocumentdbClusterPublicSnapshotFixer,
)
assert not fixer(
resource_id="test-snapshot", region=AWS_REGION_EU_WEST_1
fixer = DocumentdbClusterPublicSnapshotFixer()
assert not fixer.fix(
region=AWS_REGION_EU_WEST_1, resource_id="test-snapshot"
)

View File

@@ -12,7 +12,7 @@ from tests.providers.aws.utils import (
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_ami_public_fixer:
class TestEc2AmiPublicFixer:
@mock_aws
def test_one_private_ami(self):
ec2 = client("ec2", region_name=AWS_REGION_US_EAST_1)
@@ -42,10 +42,11 @@ class Test_ec2_ami_public_fixer:
),
):
from prowler.providers.aws.services.ec2.ec2_ami_public.ec2_ami_public_fixer import (
fixer,
Ec2AmiPublicFixer,
)
assert fixer(image_id, AWS_REGION_US_EAST_1)
fixer = Ec2AmiPublicFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1, resource_id=image_id)
@mock_aws
def test_one_public_ami(self):
@@ -85,10 +86,11 @@ class Test_ec2_ami_public_fixer:
),
):
from prowler.providers.aws.services.ec2.ec2_ami_public.ec2_ami_public_fixer import (
fixer,
Ec2AmiPublicFixer,
)
assert fixer(image_id, AWS_REGION_US_EAST_1)
fixer = Ec2AmiPublicFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1, resource_id=image_id)
@mock_aws
def test_one_public_ami_error(self):
@@ -128,7 +130,10 @@ class Test_ec2_ami_public_fixer:
),
):
from prowler.providers.aws.services.ec2.ec2_ami_public.ec2_ami_public_fixer import (
fixer,
Ec2AmiPublicFixer,
)
assert not fixer("image_id_non_existing", AWS_REGION_US_EAST_1)
fixer = Ec2AmiPublicFixer()
assert not fixer.fix(
region=AWS_REGION_US_EAST_1, resource_id="image_id_non_existing"
)

View File

@@ -5,7 +5,7 @@ from moto import mock_aws
from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider
class Test_ec2_ebs_default_encryption_fixer:
class TestEc2EbsDefaultEncryptionFixer:
@mock_aws
def test_ec2_ebs_encryption_fixer(self):
from prowler.providers.aws.services.ec2.ec2_service import EC2
@@ -23,8 +23,8 @@ class Test_ec2_ebs_default_encryption_fixer:
),
):
from prowler.providers.aws.services.ec2.ec2_ebs_default_encryption.ec2_ebs_default_encryption_fixer import (
fixer,
Ec2EbsDefaultEncryptionFixer,
)
# By default, the account has not public access blocked
assert fixer(region=AWS_REGION_US_EAST_1)
fixer = Ec2EbsDefaultEncryptionFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1)

View File

@@ -38,14 +38,13 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_ebs_public_snapshot_fixer_test:
class TestEc2EbsPublicSnapshotFixer:
@mock_aws
def test_ebs_public_snapshot(self):
with mock.patch(
"botocore.client.BaseClient._make_api_call",
new=mock_make_api_call_public_snapshot,
):
from prowler.providers.aws.services.ec2.ec2_service import EC2
aws_provider = set_mocked_aws_provider(
@@ -62,19 +61,18 @@ class Test_ec2_ebs_public_snapshot_fixer_test:
new=EC2(aws_provider),
),
):
# Test Check
from prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer import (
fixer,
Ec2EbsPublicSnapshotFixer,
)
assert fixer("testsnap", AWS_REGION_US_EAST_1)
fixer = Ec2EbsPublicSnapshotFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1, resource_id="testsnap")
@mock_aws
def test_ebs_public_snapshot_error(self):
with mock.patch(
"botocore.client.BaseClient._make_api_call", new=mock_make_api_call_error
):
from prowler.providers.aws.services.ec2.ec2_service import EC2
aws_provider = set_mocked_aws_provider(
@@ -91,9 +89,11 @@ class Test_ec2_ebs_public_snapshot_fixer_test:
new=EC2(aws_provider),
),
):
# Test Check
from prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer import (
fixer,
Ec2EbsPublicSnapshotFixer,
)
assert not fixer("testsnap", AWS_REGION_US_EAST_1)
fixer = Ec2EbsPublicSnapshotFixer()
assert not fixer.fix(
region=AWS_REGION_US_EAST_1, resource_id="testsnap"
)

View File

@@ -26,7 +26,7 @@ def mock_enable_snapshot_block_public_access(State):
return {"State": State}
class Test_ec2_ebs_snapshot_account_block_public_access_fixer:
class TestEc2EbsSnapshotAccountBlockPublicAccessFixer:
@mock_aws
def test_ec2_ebs_snapshot_account_block_public_access_fixer(self):
ec2_service = mock.MagicMock()
@@ -61,10 +61,9 @@ class Test_ec2_ebs_snapshot_account_block_public_access_fixer:
ec2_service,
),
):
from prowler.providers.aws.services.ec2.ec2_ebs_snapshot_account_block_public_access.ec2_ebs_snapshot_account_block_public_access_fixer import (
fixer,
Ec2EbsSnapshotAccountBlockPublicAccessFixer,
)
# By default, the account has not public access blocked
assert fixer(region=AWS_REGION_US_EAST_1)
fixer = Ec2EbsSnapshotAccountBlockPublicAccessFixer()
assert fixer.fix(region=AWS_REGION_US_EAST_1)

View File

@@ -27,7 +27,7 @@ def mock_modify_instance_metadata_defaults(HttpTokens):
return {"Return": True}
class Test_ec2_instance_account_imdsv2_enabled_fixer:
class TestEc2InstanceAccountImdsv2EnabledFixer:
@mock_aws
def test_ec2_instance_account_imdsv2_enabled_fixer(self):
ec2_service = mock.MagicMock()
@@ -64,8 +64,9 @@ class Test_ec2_instance_account_imdsv2_enabled_fixer:
):
from prowler.providers.aws.services.ec2.ec2_instance_account_imdsv2_enabled.ec2_instance_account_imdsv2_enabled_fixer import (
fixer,
Ec2InstanceAccountImdsv2EnabledFixer,
)
# By default, the account has not public access blocked
assert fixer(region=AWS_REGION_US_EAST_1)
assert Ec2InstanceAccountImdsv2EnabledFixer().fix(
region=AWS_REGION_US_EAST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
class TestEc2InstancePortCassandraExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cassandra_exposed_to_internet.ec2_instance_port_cassandra_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCassandraExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCassandraExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cassandra_exposed_to_internet.ec2_instance_port_cassandra_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCassandraExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortCassandraExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -223,12 +225,13 @@ class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cassandra_exposed_to_internet.ec2_instance_port_cassandra_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCassandraExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCassandraExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -280,12 +283,13 @@ class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cassandra_exposed_to_internet.ec2_instance_port_cassandra_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCassandraExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCassandraExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_all_ports(self):
@@ -343,9 +347,10 @@ class Test_ec2_instance_port_cassandra_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cassandra_exposed_to_internet.ec2_instance_port_cassandra_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCassandraExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCassandraExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
class TestEc2InstancePortCifsExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +231,13 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +295,13 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_139_port(self):
@@ -355,12 +359,13 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_with_public_ip_in_public_subnet_only_445_port(
@@ -440,9 +445,10 @@ class Test_ec2_instance_port_cifs_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_cifs_exposed_to_internet.ec2_instance_port_cifs_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortCifsExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortCifsExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
class TestEc2InstancePortElasticsearchKibanaExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,15 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert (
not Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +233,13 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +297,13 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_9200_9300_port(self):
@@ -355,12 +361,13 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_with_public_ip_in_public_subnet_only_5601_port(
@@ -440,9 +447,10 @@ class Test_ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_elasticsearch_kibana_exposed_to_internet.ec2_instance_port_elasticsearch_kibana_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortElasticsearchKibanaExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortElasticsearchKibanaExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
class TestEc2InstancePortFtpExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ftp_exposed_to_internet.ec2_instance_port_ftp_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortFtpExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortFtpExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ftp_exposed_to_internet.ec2_instance_port_ftp_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortFtpExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortFtpExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +231,13 @@ class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ftp_exposed_to_internet.ec2_instance_port_ftp_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortFtpExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortFtpExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +295,13 @@ class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ftp_exposed_to_internet.ec2_instance_port_ftp_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortFtpExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortFtpExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_both_ports(self):
@@ -355,9 +359,10 @@ class Test_ec2_instance_port_ftp_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ftp_exposed_to_internet.ec2_instance_port_ftp_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortFtpExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortFtpExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
class TestEc2InstancePortKafkaExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kafka_exposed_to_internet.ec2_instance_port_kafka_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKafkaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKafkaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -153,12 +154,13 @@ class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kafka_exposed_to_internet.ec2_instance_port_kafka_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKafkaExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortKafkaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -210,12 +212,13 @@ class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kafka_exposed_to_internet.ec2_instance_port_kafka_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKafkaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKafkaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -267,12 +270,13 @@ class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kafka_exposed_to_internet.ec2_instance_port_kafka_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKafkaExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKafkaExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_one_port(self):
@@ -330,9 +334,10 @@ class Test_ec2_instance_port_kafka_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kafka_exposed_to_internet.ec2_instance_port_kafka_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKafkaExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKafkaExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
class TestEc2InstancePortKerberosExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kerberos_exposed_to_internet.ec2_instance_port_kerberos_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKerberosExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKerberosExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kerberos_exposed_to_internet.ec2_instance_port_kerberos_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKerberosExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortKerberosExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +231,13 @@ class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kerberos_exposed_to_internet.ec2_instance_port_kerberos_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKerberosExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKerberosExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +295,13 @@ class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kerberos_exposed_to_internet.ec2_instance_port_kerberos_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKerberosExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKerberosExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_both_ports(self):
@@ -355,9 +359,10 @@ class Test_ec2_instance_port_kerberos_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_kerberos_exposed_to_internet.ec2_instance_port_kerberos_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortKerberosExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortKerberosExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
class TestEc2InstancePortLdapExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -47,8 +47,8 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
},
{
"IpProtocol": "tcp",
"FromPort": 445,
"ToPort": 445,
"FromPort": 389,
"ToPort": 636,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}, {"CidrIp": "10.0.0.0/24"}],
"Ipv6Ranges": [{"CidrIpv6": "::/0"}, {"CidrIpv6": "2001:db8::/32"}],
},
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ldap_exposed_to_internet.ec2_instance_port_ldap_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortLdapExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortLdapExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ldap_exposed_to_internet.ec2_instance_port_ldap_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortLdapExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortLdapExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +231,13 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ldap_exposed_to_internet.ec2_instance_port_ldap_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortLdapExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortLdapExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +295,13 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ldap_exposed_to_internet.ec2_instance_port_ldap_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortLdapExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortLdapExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_bot_ports(self):
@@ -355,9 +359,10 @@ class Test_ec2_instance_port_ldap_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_ldap_exposed_to_internet.ec2_instance_port_ldap_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortLdapExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortLdapExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
class TestEc2InstancePortMemcachedExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_memcached_exposed_to_internet.ec2_instance_port_memcached_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMemcachedExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMemcachedExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_memcached_exposed_to_internet.ec2_instance_port_memcached_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMemcachedExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortMemcachedExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -223,12 +225,13 @@ class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_memcached_exposed_to_internet.ec2_instance_port_memcached_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMemcachedExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMemcachedExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -280,12 +283,13 @@ class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_memcached_exposed_to_internet.ec2_instance_port_memcached_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMemcachedExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMemcachedExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_11211_port(self):
@@ -343,9 +347,10 @@ class Test_ec2_instance_port_memcached_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_memcached_exposed_to_internet.ec2_instance_port_memcached_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMemcachedExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMemcachedExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

View File

@@ -24,7 +24,7 @@ def mock_make_api_call_error(self, operation_name, kwarg):
return mock_make_api_call(self, operation_name, kwarg)
class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
class TestEc2InstancePortMongodbExposedToInternetFixer:
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_with_ip4_and_ip6(self):
# Create EC2 Mocked Resources
@@ -83,12 +83,13 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_error(self):
@@ -166,12 +167,13 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert not fixer(instance_id, AWS_REGION_EU_WEST_1)
assert not Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip4(self):
@@ -229,12 +231,13 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_private_subnet_only_with_ip6(self):
@@ -292,12 +295,13 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert fixer(instance_id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance_id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_in_public_subnet_only_27017_port(self):
@@ -355,12 +359,13 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)
@mock_aws
def test_ec2_instance_exposed_port_with_public_ip_in_public_subnet_only_27018_port(
@@ -440,9 +445,10 @@ class Test_ec2_instance_port_mongodb_exposed_to_internet_fixer:
new=EC2(aws_provider),
),
):
# Test Fixer
from prowler.providers.aws.services.ec2.ec2_instance_port_mongodb_exposed_to_internet.ec2_instance_port_mongodb_exposed_to_internet_fixer import (
fixer,
Ec2InstancePortMongodbExposedToInternetFixer,
)
assert fixer(instance.id, AWS_REGION_EU_WEST_1)
assert Ec2InstancePortMongodbExposedToInternetFixer().fix(
resource_id=instance.id, region=AWS_REGION_EU_WEST_1
)

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