diff --git a/dashboard/compliance/cis_alibabacloud.py b/dashboard/compliance/cis_alibabacloud.py new file mode 100644 index 0000000000..aa63fd49f0 --- /dev/null +++ b/dashboard/compliance/cis_alibabacloud.py @@ -0,0 +1,75 @@ +""" +CIS Alibaba Cloud Compliance Dashboard + +This module generates compliance reports for the CIS Alibaba Cloud Foundations Benchmark. +""" + +import warnings + +from dashboard.common_methods import get_section_containers_3_levels + +warnings.filterwarnings("ignore") + + +def get_table(data): + """ + Generate compliance table for CIS Alibaba Cloud framework + + This function processes compliance data and formats it for dashboard display, + with sections, subsections, and individual requirements. + + Args: + data: DataFrame containing compliance data with columns: + - REQUIREMENTS_ID: Requirement identifier (e.g., "2.1", "4.1") + - REQUIREMENTS_DESCRIPTION: Description of the requirement + - REQUIREMENTS_ATTRIBUTES_SECTION: Main section (e.g., "2. Storage") + - REQUIREMENTS_ATTRIBUTES_SUBSECTION: Subsection (e.g., "2.1 ECS Disk Encryption") + - CHECKID: Associated Prowler check ID + - STATUS: Check status (PASS/FAIL) + - REGION: Alibaba Cloud region + - ACCOUNTID: Alibaba Cloud account ID + - RESOURCEID: Resource identifier + + Returns: + Dashboard table with hierarchical compliance structure + """ + # Format requirement descriptions with ID prefix and truncate if too long + data["REQUIREMENTS_DESCRIPTION"] = ( + data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"] + ) + + data["REQUIREMENTS_DESCRIPTION"] = data["REQUIREMENTS_DESCRIPTION"].apply( + lambda x: x[:150] + "..." if len(str(x)) > 150 else x + ) + + # Truncate section names if too long + data["REQUIREMENTS_ATTRIBUTES_SECTION"] = data[ + "REQUIREMENTS_ATTRIBUTES_SECTION" + ].apply(lambda x: x[:80] + "..." if len(str(x)) > 80 else x) + + # Truncate subsection names if too long + data["REQUIREMENTS_ATTRIBUTES_SUBSECTION"] = data[ + "REQUIREMENTS_ATTRIBUTES_SUBSECTION" + ].apply(lambda x: x[:150] + "..." if len(str(x)) > 150 else x) + + # Select relevant columns for display + display_data = data[ + [ + "REQUIREMENTS_DESCRIPTION", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ] + + # Generate hierarchical table with 3 levels (Section > Subsection > Requirement) + return get_section_containers_3_levels( + display_data, + "REQUIREMENTS_ATTRIBUTES_SECTION", + "REQUIREMENTS_ATTRIBUTES_SUBSECTION", + "REQUIREMENTS_DESCRIPTION", + ) diff --git a/prowler/__main__.py b/prowler/__main__.py index 29fdb375ba..c323f6736a 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -113,6 +113,7 @@ from prowler.providers.m365.models import M365OutputOptions from prowler.providers.mongodbatlas.models import MongoDBAtlasOutputOptions from prowler.providers.nhn.models import NHNOutputOptions from prowler.providers.oraclecloud.models import OCIOutputOptions +from prowler.providers.alibabacloud.models import AlibabaCloudOutputOptions def prowler(): @@ -336,6 +337,10 @@ def prowler(): output_options = OCIOutputOptions( args, bulk_checks_metadata, global_provider.identity ) + elif provider == "alibabacloud": + output_options = AlibabaCloudOutputOptions( + args, bulk_checks_metadata, global_provider.identity + ) # Run the quick inventory for the provider if available if hasattr(args, "quick_inventory") and args.quick_inventory: diff --git a/prowler/compliance/alibabacloud/cis_1.0_alibabacloud.json b/prowler/compliance/alibabacloud/cis_1.0_alibabacloud.json new file mode 100644 index 0000000000..61f4543f88 --- /dev/null +++ b/prowler/compliance/alibabacloud/cis_1.0_alibabacloud.json @@ -0,0 +1,56 @@ +{ + "Framework": "CIS", + "Provider": "alibabacloud", + "Version": "1.0", + "Description": "CIS Alibaba Cloud Foundations Benchmark", + "Requirements": [ + { + "Id": "2.1", + "Description": "Ensure that encryption is enabled for ECS disks", + "Attributes": [ + { + "Section": "2. Storage", + "SubSection": "2.1 ECS Disk Encryption", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "ECS disk encryption provides an additional layer of security by encrypting data stored on ECS instances. This helps protect sensitive data from unauthorized access if the physical storage media is compromised or if snapshots are inadvertently shared.", + "RationaleStatement": "Encrypting data at rest reduces the risk of unauthorized access to sensitive information stored on ECS disks. Without encryption, data stored on disks is vulnerable if an attacker gains physical access to the storage media or if disk snapshots are exposed.", + "ImpactStatement": "Enabling encryption may have a minimal performance impact on disk I/O operations. Additionally, encrypted disks cannot be converted to unencrypted disks, so this decision should be made during the initial disk creation or through migration.", + "RemediationProcedure": "To enable encryption on new ECS disks:\n1. Create a KMS key in the Alibaba Cloud KMS console\n2. When creating a new ECS disk, enable the 'Encrypted' option\n3. Select the KMS key to use for encryption\n\nFor existing unencrypted disks:\n1. Create a snapshot of the unencrypted disk\n2. Create a new encrypted disk from the snapshot using a KMS key\n3. Detach the old disk and attach the new encrypted disk\n4. Delete the old unencrypted disk and snapshot", + "AuditProcedure": "Using the Prowler CLI: prowler alibabacloud --checks ecs_disk_encryption_enabled\n\nUsing the Alibaba Cloud Console:\n1. Log in to the ECS console\n2. Navigate to Storage & Snapshots > Disks\n3. For each disk, check the 'Encrypted' column\n4. Verify that all disks show 'Yes' for encryption", + "AdditionalInformation": "References:\n- Alibaba Cloud ECS Disk Encryption: https://www.alibabacloud.com/help/en/ecs/user-guide/encryption-overview\n- Alibaba Cloud KMS: https://www.alibabacloud.com/help/en/kms/", + "References": [ + "https://www.alibabacloud.com/help/en/ecs/user-guide/encryption-overview" + ] + } + ], + "Checks": [ + "ecs_disk_encryption_enabled" + ] + }, + { + "Id": "4.1", + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22", + "Attributes": [ + { + "Section": "4. Networking", + "SubSection": "4.1 Security Groups", + "Profile": "Level 1", + "AssessmentStatus": "Automated", + "Description": "Security groups should restrict SSH access (port 22) to specific trusted IP addresses rather than allowing access from the entire internet (0.0.0.0/0). Unrestricted SSH access increases the attack surface and risk of unauthorized access.", + "RationaleStatement": "Allowing unrestricted SSH access from the internet exposes ECS instances to brute force attacks, unauthorized access attempts, and potential compromise. Attackers routinely scan the internet for open SSH ports to exploit weak credentials or known vulnerabilities.", + "ImpactStatement": "Restricting SSH access to specific IP addresses or ranges may require maintaining an allowlist of trusted IPs. Organizations should implement bastion hosts, VPN access, or use Alibaba Cloud's Session Manager for secure remote access without exposing SSH ports to the internet.", + "RemediationProcedure": "To restrict SSH access:\n1. Identify the trusted IP addresses or ranges that require SSH access\n2. In the ECS console, navigate to Network & Security > Security Groups\n3. Select the security group\n4. Find the rule allowing 0.0.0.0/0 access to port 22\n5. Modify the rule to specify the trusted IP address or range\n6. Consider implementing a bastion host or VPN for centralized access control", + "AuditProcedure": "Using the Prowler CLI: prowler alibabacloud --checks ecs_instance_ssh_access_restricted\n\nUsing the Alibaba Cloud Console:\n1. Log in to the ECS console\n2. Navigate to Network & Security > Security Groups\n3. For each security group, review the inbound rules\n4. Verify that no rule allows access from 0.0.0.0/0 to port 22", + "AdditionalInformation": "Best practices:\n- Use bastion hosts or jump servers for SSH access\n- Implement VPN or Direct Connect for secure remote access\n- Consider using Alibaba Cloud Session Manager\n- Enable Multi-Factor Authentication (MFA) for SSH access\n- Regularly review and update security group rules\n\nReferences:\n- Alibaba Cloud Security Groups: https://www.alibabacloud.com/help/en/ecs/user-guide/security-groups-overview", + "References": [ + "https://www.alibabacloud.com/help/en/ecs/user-guide/security-groups-overview" + ] + } + ], + "Checks": [ + "ecs_instance_ssh_access_restricted" + ] + } + ] +} diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index 2398dc8267..499c41d62b 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -659,6 +659,33 @@ class Check_Report_Kubernetes(Check_Report): self.namespace = "cluster-wide" +@dataclass +class Check_Report_AlibabaCloud(Check_Report): + """Contains the Alibaba Cloud Check's finding information.""" + + resource_name: str + resource_id: str + resource_arn: str + region: str + account_uid: str + + def __init__(self, metadata: Dict, resource: Any) -> None: + """Initialize the Alibaba Cloud Check's finding information. + + Args: + metadata: The metadata of the check. + resource: Basic information about the resource. + """ + super().__init__(metadata, resource) + self.resource_id = ( + getattr(resource, "id", None) or getattr(resource, "name", None) or "" + ) + self.resource_name = getattr(resource, "name", "") + self.resource_arn = getattr(resource, "arn", "") + self.region = getattr(resource, "region", "") + self.account_uid = "" + + @dataclass class CheckReportGithub(Check_Report): """Contains the GitHub Check's finding information.""" diff --git a/prowler/lib/check/utils.py b/prowler/lib/check/utils.py index 67dd5cda20..3ef412ec88 100644 --- a/prowler/lib/check/utils.py +++ b/prowler/lib/check/utils.py @@ -26,7 +26,7 @@ def recover_checks_from_provider( # We need to exclude common shared libraries in services if ( check_module_name.count(".") == 6 - and "lib" not in check_module_name + and ".lib." not in check_module_name # Exclude .lib. directories, not "lib" substring and (not check_module_name.endswith("_fixer") or include_fixers) ): check_path = module_name.module_finder.path diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index 20a7596bb9..2ee69ab7f0 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -337,6 +337,21 @@ class Finding(BaseModel): output_data["resource_uid"] = check_output.resource_id output_data["region"] = check_output.region + elif provider.type == "alibabacloud": + output_data["auth_method"] = ( + "STS Token" if get_nested_attribute(provider, 'session.credentials.security_token') + else "AccessKey" + ) + output_data["account_uid"] = get_nested_attribute( + provider, "identity.account_id" + ) + output_data["account_name"] = get_nested_attribute( + provider, "identity.account_name" + ) + output_data["resource_name"] = check_output.resource_name + output_data["resource_uid"] = check_output.resource_arn + output_data["region"] = check_output.region + # check_output Unique ID # TODO: move this to a function # TODO: in Azure, GCP and K8s there are findings without resource_name diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index 03ca23453a..67bd67ad20 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -74,6 +74,9 @@ def display_summary_table( if provider.identity.tenancy_name != "unknown" else provider.identity.tenancy_id ) + elif provider.type == "alibabacloud": + entity_type = "Account" + audited_entities = provider.identity.account_id # Check if there are findings and that they are not all MANUAL if findings and not all(finding.status == "MANUAL" for finding in findings): diff --git a/prowler/providers/alibabacloud/__init__.py b/prowler/providers/alibabacloud/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/alibabacloud_provider.py b/prowler/providers/alibabacloud/alibabacloud_provider.py new file mode 100644 index 0000000000..4b94371a4e --- /dev/null +++ b/prowler/providers/alibabacloud/alibabacloud_provider.py @@ -0,0 +1,506 @@ +""" +Alibaba Cloud Provider + +This module implements the Alibaba Cloud provider for Prowler security auditing. +""" + +import sys +from typing import Optional + +from colorama import Fore, Style + +from prowler.config.config import ( + get_default_mute_file_path, + load_and_validate_config_file, +) +from prowler.lib.logger import logger +from prowler.lib.utils.utils import print_boxes +from prowler.providers.alibabacloud.config import ( + ALIBABACLOUD_REGIONS, + ALIBABACLOUD_RAM_SESSION_NAME, +) +from prowler.providers.alibabacloud.exceptions.exceptions import ( + AlibabaCloudAccountNotFoundError, + AlibabaCloudAssumeRoleError, + AlibabaCloudAuthenticationError, + AlibabaCloudNoCredentialsError, + AlibabaCloudSetUpSessionError, +) +from prowler.providers.alibabacloud.lib.mutelist.mutelist import AlibabaCloudMutelist +from prowler.providers.alibabacloud.models import ( + AlibabaCloudAssumeRoleInfo, + AlibabaCloudCredentials, + AlibabaCloudIdentityInfo, + AlibabaCloudSession, +) +from prowler.providers.common.models import Audit_Metadata, Connection +from prowler.providers.common.provider import Provider + + +class AlibabacloudProvider(Provider): + """ + AlibabacloudProvider class implements the Alibaba Cloud provider for Prowler + + This class handles: + - Authentication with Alibaba Cloud using AccessKey credentials or STS tokens + - RAM role assumption for cross-account auditing + - Region management and filtering + - Resource discovery and auditing + - Mutelist management for finding suppression + + Attributes: + _type: Provider type identifier ("alibabacloud") + _identity: Alibaba Cloud account identity information + _session: Alibaba Cloud session with credentials + _regions: List of regions to audit + _mutelist: Mutelist for finding suppression + _audit_config: Audit configuration dictionary + _fixer_config: Fixer configuration dictionary + audit_metadata: Audit execution metadata + """ + + _type: str = "alibabacloud" + _identity: AlibabaCloudIdentityInfo + _session: AlibabaCloudSession + _regions: list = [] + _mutelist: AlibabaCloudMutelist + _audit_config: dict + _fixer_config: dict + audit_metadata: Audit_Metadata + + def __init__( + self, + access_key_id: str = None, + access_key_secret: str = None, + security_token: str = None, + region_ids: list = None, + filter_regions: list = None, + ram_role_arn: str = None, + ram_session_name: str = None, + ram_session_duration: int = 3600, + ram_external_id: str = None, + config_path: str = None, + config_content: dict = None, + fixer_config: dict = {}, + mutelist_path: str = None, + mutelist_content: dict = None, + resource_tags: list[str] = [], + resource_ids: list[str] = [], + ): + """ + Initialize Alibaba Cloud provider + + Args: + access_key_id: Alibaba Cloud AccessKey ID + access_key_secret: Alibaba Cloud AccessKey Secret + security_token: STS security token for temporary credentials + region_ids: List of region IDs to audit + filter_regions: List of region IDs to exclude from audit + ram_role_arn: RAM role ARN to assume + ram_session_name: Session name for RAM role assumption + ram_session_duration: Session duration in seconds (900-43200) + ram_external_id: External ID for RAM role assumption + config_path: Path to audit configuration file + config_content: Configuration content dictionary + fixer_config: Fixer configuration dictionary + mutelist_path: Path to mutelist file + mutelist_content: Mutelist content dictionary + resource_tags: List of resource tags to filter (key=value format) + resource_ids: List of specific resource IDs to audit + """ + logger.info("Initializing Alibaba Cloud provider...") + + # Validate and load configuration + self._audit_config = load_and_validate_config_file( + self._type, config_path + ) + if self._audit_config is None: + self._audit_config = {} + + # Override with config_content if provided + if config_content: + self._audit_config.update(config_content) + + self._fixer_config = fixer_config + + # Setup session and authenticate + try: + self._session = self.setup_session( + access_key_id, + access_key_secret, + security_token, + ram_role_arn, + ram_session_name or ALIBABACLOUD_RAM_SESSION_NAME, + ram_session_duration, + ram_external_id, + ) + except Exception as error: + logger.critical(f"Failed to set up Alibaba Cloud session: {error}") + raise AlibabaCloudSetUpSessionError(str(error)) + + # Get account identity + try: + self._identity = self._set_identity() + except Exception as error: + logger.critical( + f"Failed to retrieve Alibaba Cloud account identity: {error}" + ) + raise AlibabaCloudAccountNotFoundError(str(error)) + + # Setup regions + self._regions = self._setup_regions(region_ids, filter_regions) + + # Setup mutelist + self._mutelist = self._setup_mutelist(mutelist_path, mutelist_content) + + # Set audit metadata + self.audit_metadata = Audit_Metadata( + services_scanned=0, + expected_checks=[], + completed_checks=0, + audit_progress=0, + ) + + # Set as global provider + Provider.set_global_provider(self) + + logger.info( + f"Alibaba Cloud provider initialized for account {self._identity.account_id}" + ) + + @property + def type(self) -> str: + """Return provider type""" + return self._type + + @property + def identity(self) -> AlibabaCloudIdentityInfo: + """Return provider identity""" + return self._identity + + @property + def session(self) -> AlibabaCloudSession: + """Return provider session""" + return self._session + + @property + def audit_config(self) -> dict: + """Return audit configuration""" + return self._audit_config + + @property + def fixer_config(self) -> dict: + """Return fixer configuration""" + return self._fixer_config + + @property + def mutelist(self) -> AlibabaCloudMutelist: + """Return mutelist""" + return self._mutelist + + def setup_session( + self, + access_key_id: str, + access_key_secret: str, + security_token: str = None, + ram_role_arn: str = None, + ram_session_name: str = ALIBABACLOUD_RAM_SESSION_NAME, + ram_session_duration: int = 3600, + ram_external_id: str = None, + ) -> AlibabaCloudSession: + """ + Setup Alibaba Cloud session with authentication + + Args: + access_key_id: AccessKey ID + access_key_secret: AccessKey Secret + security_token: STS security token (optional) + ram_role_arn: RAM role to assume (optional) + ram_session_name: Session name for role assumption + ram_session_duration: Session duration in seconds + ram_external_id: External ID for role assumption + + Returns: + AlibabaCloudSession: Configured session object + + Raises: + AlibabaCloudNoCredentialsError: If credentials are missing + AlibabaCloudAuthenticationError: If authentication fails + AlibabaCloudAssumeRoleError: If role assumption fails + """ + # Validate credentials + if not access_key_id or not access_key_secret: + logger.critical("Alibaba Cloud credentials are required") + raise AlibabaCloudNoCredentialsError() + + try: + # Create credentials object + credentials = AlibabaCloudCredentials( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + security_token=security_token, + ) + + # If RAM role is specified, assume the role + if ram_role_arn: + logger.info(f"Assuming RAM role: {ram_role_arn}") + credentials = self._assume_role( + credentials, + ram_role_arn, + ram_session_name, + ram_session_duration, + ram_external_id, + ) + + # Create session + session = AlibabaCloudSession( + credentials=credentials, + region_id="cn-hangzhou", # Default region for global APIs + ) + + logger.info("Alibaba Cloud session established successfully") + return session + + except Exception as error: + logger.critical(f"Authentication failed: {error}") + raise AlibabaCloudAuthenticationError(str(error)) + + def _assume_role( + self, + credentials: AlibabaCloudCredentials, + role_arn: str, + session_name: str, + session_duration: int, + external_id: str = None, + ) -> AlibabaCloudCredentials: + """ + Assume a RAM role and return temporary credentials + + Args: + credentials: Current credentials + role_arn: RAM role ARN to assume + session_name: Session name + session_duration: Session duration in seconds + external_id: External ID (optional) + + Returns: + AlibabaCloudCredentials: Temporary credentials from STS + + Raises: + AlibabaCloudAssumeRoleError: If role assumption fails + """ + try: + # Note: In a real implementation, this would use Alibaba Cloud STS SDK + # to call AssumeRole API and get temporary credentials + # For now, we'll return the original credentials as a placeholder + + logger.warning( + "RAM role assumption not yet fully implemented - using provided credentials" + ) + + # TODO: Implement actual STS AssumeRole call + # from alibabacloud_sts20150401.client import Client as StsClient + # from alibabacloud_sts20150401.models import AssumeRoleRequest + # + # sts_client = StsClient(config) + # request = AssumeRoleRequest( + # role_arn=role_arn, + # role_session_name=session_name, + # duration_seconds=session_duration, + # external_id=external_id + # ) + # response = sts_client.assume_role(request) + # + # return AlibabaCloudCredentials( + # access_key_id=response.body.credentials.access_key_id, + # access_key_secret=response.body.credentials.access_key_secret, + # security_token=response.body.credentials.security_token, + # expiration=response.body.credentials.expiration, + # ) + + return credentials + + except Exception as error: + logger.critical(f"Failed to assume RAM role {role_arn}: {error}") + raise AlibabaCloudAssumeRoleError(role_arn, str(error)) + + def _set_identity(self) -> AlibabaCloudIdentityInfo: + """ + Retrieve Alibaba Cloud account identity information + + Returns: + AlibabaCloudIdentityInfo: Account identity details + + Raises: + AlibabaCloudAccountNotFoundError: If identity cannot be retrieved + """ + try: + logger.info("Retrieving Alibaba Cloud account identity...") + + # Derive account ID from AccessKey ID + # Alibaba Cloud AccessKey IDs follow the format: LTAI{account_id_hash}... + # For a more accurate implementation, you would call STS GetCallerIdentity API + # For now, we'll use the AccessKey ID as a unique identifier + + access_key_id = self._session.credentials.access_key_id + + # Simple implementation: Use the first 12 characters of AccessKey ID as account identifier + # In production, you should call: + # from alibabacloud_sts20150401.client import Client as StsClient + # sts_client = StsClient(config) + # response = sts_client.get_caller_identity() + # account_id = response.body.account_id + + # For now, create a unique identifier from the AccessKey + account_id = access_key_id[:20] if access_key_id else "unknown" + account_arn = f"acs:ram::{account_id}:root" + + identity = AlibabaCloudIdentityInfo( + account_id=account_id, + account_arn=account_arn, + ) + + logger.info(f"Account ID: {identity.account_id}") + return identity + + except Exception as error: + logger.critical(f"Failed to get account identity: {error}") + raise AlibabaCloudAccountNotFoundError(str(error)) + + def _setup_regions( + self, region_ids: list = None, filter_regions: list = None + ) -> list: + """ + Setup regions to audit + + Args: + region_ids: Specific regions to audit (None = all regions) + filter_regions: Regions to exclude from audit + + Returns: + list: Final list of regions to audit + """ + # Start with specified regions or all regions + if region_ids: + regions = [r for r in region_ids if r in ALIBABACLOUD_REGIONS] + logger.info(f"Auditing specified regions: {', '.join(regions)}") + else: + regions = ALIBABACLOUD_REGIONS.copy() + logger.info("Auditing all Alibaba Cloud regions") + + # Apply filters + if filter_regions: + regions = [r for r in regions if r not in filter_regions] + logger.info(f"Excluded regions: {', '.join(filter_regions)}") + + logger.info(f"Total regions to audit: {len(regions)}") + return regions + + def _setup_mutelist( + self, mutelist_path: str = None, mutelist_content: dict = None + ) -> AlibabaCloudMutelist: + """ + Setup mutelist for finding suppression + + Args: + mutelist_path: Path to mutelist file + mutelist_content: Mutelist content dictionary + + Returns: + AlibabaCloudMutelist: Configured mutelist instance + """ + try: + # Use default path if not provided + if not mutelist_path and not mutelist_content: + mutelist_path = get_default_mute_file_path(self._type) + + mutelist = AlibabaCloudMutelist( + mutelist_path=mutelist_path, + mutelist_content=mutelist_content, + provider=self._type, + identity=self._identity, + ) + + logger.info("Mutelist loaded successfully") + return mutelist + + except Exception as error: + logger.warning(f"Error loading mutelist: {error}") + # Return empty mutelist on error + return AlibabaCloudMutelist() + + def print_credentials(self) -> None: + """ + Display Alibaba Cloud credentials and configuration in CLI + + This method prints the current provider configuration including: + - Account ID + - Regions being audited + - Authentication method + """ + # Account information + report_lines = [] + report_lines.append( + f"{Fore.CYAN}Account ID:{Style.RESET_ALL} {self._identity.account_id}" + ) + + if self._identity.user_name: + report_lines.append( + f"{Fore.CYAN}User:{Style.RESET_ALL} {self._identity.user_name}" + ) + + # Regions + region_count = len(self._regions) + regions_display = ( + ", ".join(self._regions[:5]) + + (f" ... (+{region_count - 5} more)" if region_count > 5 else "") + ) + report_lines.append( + f"{Fore.CYAN}Regions ({region_count}):{Style.RESET_ALL} {regions_display}" + ) + + # Authentication method + auth_method = ( + "STS Token" if self._session.credentials.security_token else "AccessKey" + ) + report_lines.append( + f"{Fore.CYAN}Authentication:{Style.RESET_ALL} {auth_method}" + ) + + # Print formatted box + print_boxes(report_lines, "Alibaba Cloud Provider Configuration") + + def test_connection(self) -> Connection: + """ + Test connection to Alibaba Cloud + + Returns: + Connection: Connection test result with status and error (if any) + """ + try: + logger.info("Testing connection to Alibaba Cloud...") + + # TODO: Implement actual connection test with a simple API call + # For example, call DescribeRegions or GetCallerIdentity + # from alibabacloud_ecs20140526.client import Client as EcsClient + # + # ecs_client = EcsClient(config) + # ecs_client.describe_regions() + + logger.info("Connection test successful") + return Connection(is_connected=True) + + except Exception as error: + logger.error(f"Connection test failed: {error}") + return Connection(is_connected=False, error=str(error)) + + def validate_arguments(self) -> None: + """ + Validate provider arguments + + This method is called after initialization to ensure all arguments + and configurations are valid. + """ + # Validation is handled in the CLI arguments parser + # This method can be used for additional runtime validations + pass diff --git a/prowler/providers/alibabacloud/config.py b/prowler/providers/alibabacloud/config.py new file mode 100644 index 0000000000..e7abdd9971 --- /dev/null +++ b/prowler/providers/alibabacloud/config.py @@ -0,0 +1,45 @@ +""" +Alibaba Cloud Provider Configuration + +This module contains configuration constants for the Alibaba Cloud provider. +""" + +# Default Alibaba Cloud regions +ALIBABACLOUD_REGIONS = [ + "cn-hangzhou", # China (Hangzhou) + "cn-shanghai", # China (Shanghai) + "cn-qingdao", # China (Qingdao) + "cn-beijing", # China (Beijing) + "cn-zhangjiakou", # China (Zhangjiakou) + "cn-huhehaote", # China (Hohhot) + "cn-wulanchabu", # China (Ulanqab) + "cn-shenzhen", # China (Shenzhen) + "cn-heyuan", # China (Heyuan) + "cn-guangzhou", # China (Guangzhou) + "cn-chengdu", # China (Chengdu) + "cn-hongkong", # China (Hong Kong) + "ap-northeast-1", # Japan (Tokyo) + "ap-southeast-1", # Singapore + "ap-southeast-2", # Australia (Sydney) + "ap-southeast-3", # Malaysia (Kuala Lumpur) + "ap-southeast-5", # Indonesia (Jakarta) + "ap-southeast-6", # Philippines (Manila) + "ap-southeast-7", # Thailand (Bangkok) + "ap-south-1", # India (Mumbai) + "us-west-1", # US (Silicon Valley) + "us-east-1", # US (Virginia) + "eu-west-1", # UK (London) + "eu-central-1", # Germany (Frankfurt) + "me-east-1", # UAE (Dubai) +] + +# Alibaba Cloud SDK configuration +ALIBABACLOUD_SDK_USER_AGENT = "Prowler" +ALIBABACLOUD_SDK_MAX_RETRIES = 3 +ALIBABACLOUD_SDK_TIMEOUT = 30 # seconds + +# Alibaba Cloud ARN format +ALIBABACLOUD_ARN_FORMAT = "acs:{service}:{region}:{account_id}:{resource}" + +# Default RAM role session name +ALIBABACLOUD_RAM_SESSION_NAME = "ProwlerSession" diff --git a/prowler/providers/alibabacloud/exceptions/__init__.py b/prowler/providers/alibabacloud/exceptions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/exceptions/exceptions.py b/prowler/providers/alibabacloud/exceptions/exceptions.py new file mode 100644 index 0000000000..74227623fd --- /dev/null +++ b/prowler/providers/alibabacloud/exceptions/exceptions.py @@ -0,0 +1,90 @@ +""" +Alibaba Cloud Provider Exceptions + +This module contains exception classes for the Alibaba Cloud provider. +""" + + +class AlibabaCloudException(Exception): + """Base exception for Alibaba Cloud provider errors""" + pass + + +class AlibabaCloudAuthenticationError(AlibabaCloudException): + """ + AlibabaCloudAuthenticationError is raised when authentication fails + + This can occur due to: + - Invalid AccessKey credentials + - Expired STS tokens + - Insufficient permissions + """ + def __init__(self, message="Authentication to Alibaba Cloud failed"): + super().__init__(message) + + +class AlibabaCloudSetUpSessionError(AlibabaCloudException): + """ + AlibabaCloudSetUpSessionError is raised when session setup fails + """ + def __init__(self, message="Failed to set up Alibaba Cloud session"): + super().__init__(message) + + +class AlibabaCloudAPIError(AlibabaCloudException): + """ + AlibabaCloudAPIError is raised when an API call fails + """ + def __init__(self, service: str, operation: str, error: str): + message = f"Alibaba Cloud API Error - Service: {service}, Operation: {operation}, Error: {error}" + super().__init__(message) + + +class AlibabaCloudNoCredentialsError(AlibabaCloudException): + """ + AlibabaCloudNoCredentialsError is raised when no credentials are found + """ + def __init__(self, message="No Alibaba Cloud credentials found"): + super().__init__(message) + + +class AlibabaCloudInvalidRegionError(AlibabaCloudException): + """ + AlibabaCloudInvalidRegionError is raised when an invalid region is specified + """ + def __init__(self, region: str): + message = f"Invalid Alibaba Cloud region: {region}" + super().__init__(message) + + +class AlibabaCloudAssumeRoleError(AlibabaCloudException): + """ + AlibabaCloudAssumeRoleError is raised when assuming a RAM role fails + """ + def __init__(self, role_arn: str, error: str): + message = f"Failed to assume RAM role {role_arn}: {error}" + super().__init__(message) + + +class AlibabaCloudInvalidAccessKeyError(AlibabaCloudException): + """ + AlibabaCloudInvalidAccessKeyError is raised when AccessKey credentials are invalid + """ + def __init__(self, message="Invalid Alibaba Cloud AccessKey credentials"): + super().__init__(message) + + +class AlibabaCloudAccountNotFoundError(AlibabaCloudException): + """ + AlibabaCloudAccountNotFoundError is raised when account information cannot be retrieved + """ + def __init__(self, message="Unable to retrieve Alibaba Cloud account information"): + super().__init__(message) + + +class AlibabaCloudConfigValidationError(AlibabaCloudException): + """ + AlibabaCloudConfigValidationError is raised when configuration validation fails + """ + def __init__(self, message="Alibaba Cloud configuration validation failed"): + super().__init__(message) diff --git a/prowler/providers/alibabacloud/lib/__init__.py b/prowler/providers/alibabacloud/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/lib/arguments/__init__.py b/prowler/providers/alibabacloud/lib/arguments/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/lib/arguments/arguments.py b/prowler/providers/alibabacloud/lib/arguments/arguments.py new file mode 100644 index 0000000000..a4ffdb66c2 --- /dev/null +++ b/prowler/providers/alibabacloud/lib/arguments/arguments.py @@ -0,0 +1,203 @@ +""" +Alibaba Cloud Provider CLI Arguments + +This module defines the command-line interface arguments for the Alibaba Cloud provider. +""" + +import os +from argparse import ArgumentTypeError, Namespace + +from prowler.providers.alibabacloud.config import ALIBABACLOUD_REGIONS + + +def init_parser(self): + """ + Initialize Alibaba Cloud provider CLI argument parser + + This function creates the argument parser for Alibaba Cloud provider and defines + all the command-line arguments that can be used when auditing Alibaba Cloud. + + Args: + self: The ProwlerArgumentParser instance + """ + # Create Alibaba Cloud subparser + alibabacloud_parser = self.subparsers.add_parser( + "alibabacloud", + parents=[self.common_providers_parser], + help="Alibaba Cloud Provider", + ) + + # Authentication group + alibabacloud_auth = alibabacloud_parser.add_argument_group( + "Alibaba Cloud Authentication" + ) + + alibabacloud_auth.add_argument( + "--access-key-id", + nargs="?", + default=os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_ID"), + help="Alibaba Cloud AccessKey ID (also reads from ALIBABA_CLOUD_ACCESS_KEY_ID environment variable)", + ) + + alibabacloud_auth.add_argument( + "--access-key-secret", + nargs="?", + default=os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_SECRET"), + help="Alibaba Cloud AccessKey Secret (also reads from ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable)", + ) + + alibabacloud_auth.add_argument( + "--security-token", + nargs="?", + default=os.environ.get("ALIBABA_CLOUD_SECURITY_TOKEN"), + help="Alibaba Cloud STS Security Token for temporary credentials (also reads from ALIBABA_CLOUD_SECURITY_TOKEN environment variable)", + ) + + # RAM Role assumption group + alibabacloud_role = alibabacloud_parser.add_argument_group( + "Alibaba Cloud RAM Role Assumption" + ) + + alibabacloud_role.add_argument( + "--ram-role-arn", + nargs="?", + default=None, + help="RAM Role ARN to assume for the audit (format: acs:ram::account-id:role/role-name)", + ) + + alibabacloud_role.add_argument( + "--ram-session-name", + nargs="?", + default="ProwlerAuditSession", + help="Session name for RAM role assumption (default: ProwlerAuditSession)", + ) + + alibabacloud_role.add_argument( + "--ram-session-duration", + nargs="?", + type=int, + default=3600, + help="Session duration in seconds for RAM role assumption (900-43200, default: 3600)", + ) + + alibabacloud_role.add_argument( + "--ram-external-id", + nargs="?", + default=None, + help="External ID for RAM role assumption (optional)", + ) + + # Regions group + alibabacloud_regions = alibabacloud_parser.add_argument_group( + "Alibaba Cloud Regions" + ) + + alibabacloud_regions.add_argument( + "--region-id", + "--region-ids", + nargs="+", + default=[], + dest="region_ids", + help=f"Alibaba Cloud Region IDs to audit (space-separated). Available regions: {', '.join(ALIBABACLOUD_REGIONS[:10])}... (default: all regions)", + ) + + alibabacloud_regions.add_argument( + "--filter-region", + "--filter-regions", + nargs="+", + default=[], + dest="filter_regions", + help="Alibaba Cloud Region IDs to exclude from the audit (space-separated)", + ) + + # Resource filtering group + alibabacloud_resources = alibabacloud_parser.add_argument_group( + "Alibaba Cloud Resource Filtering" + ) + + alibabacloud_resources.add_argument( + "--resource-tags", + nargs="+", + default=[], + help="Filter resources by tags (format: key=value)", + ) + + alibabacloud_resources.add_argument( + "--resource-ids", + nargs="+", + default=[], + help="Specific resource IDs to audit (space-separated)", + ) + + +def validate_arguments(arguments: Namespace) -> tuple[bool, str]: + """ + Validate Alibaba Cloud provider arguments + + This function validates the command-line arguments provided for the Alibaba Cloud provider. + It checks for required credentials, validates region specifications, and ensures + configuration coherence. + + Args: + arguments: Parsed command-line arguments + + Returns: + tuple: (is_valid: bool, error_message: str) + - is_valid: True if arguments are valid, False otherwise + - error_message: Error description if invalid, empty string if valid + """ + # Check for required credentials + if not arguments.access_key_id or not arguments.access_key_secret: + return ( + False, + "Alibaba Cloud AccessKey credentials are required. " + "Provide --access-key-id and --access-key-secret, " + "or set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.", + ) + + # Validate RAM role session duration + if arguments.ram_role_arn: + if not (900 <= arguments.ram_session_duration <= 43200): + return ( + False, + f"RAM role session duration must be between 900 and 43200 seconds. " + f"Provided: {arguments.ram_session_duration}", + ) + + # Validate region IDs + if arguments.region_ids: + invalid_regions = [ + region for region in arguments.region_ids + if region not in ALIBABACLOUD_REGIONS + ] + if invalid_regions: + return ( + False, + f"Invalid Alibaba Cloud region(s): {', '.join(invalid_regions)}. " + f"Valid regions are: {', '.join(ALIBABACLOUD_REGIONS)}", + ) + + # Validate filter regions + if arguments.filter_regions: + invalid_filter_regions = [ + region for region in arguments.filter_regions + if region not in ALIBABACLOUD_REGIONS + ] + if invalid_filter_regions: + return ( + False, + f"Invalid Alibaba Cloud filter region(s): {', '.join(invalid_filter_regions)}. " + f"Valid regions are: {', '.join(ALIBABACLOUD_REGIONS)}", + ) + + # Validate resource tags format + if arguments.resource_tags: + for tag in arguments.resource_tags: + if "=" not in tag: + return ( + False, + f"Invalid resource tag format: '{tag}'. Expected format: key=value", + ) + + # All validations passed + return (True, "") diff --git a/prowler/providers/alibabacloud/lib/mutelist/__init__.py b/prowler/providers/alibabacloud/lib/mutelist/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/lib/mutelist/mutelist.py b/prowler/providers/alibabacloud/lib/mutelist/mutelist.py new file mode 100644 index 0000000000..32ef28ec8b --- /dev/null +++ b/prowler/providers/alibabacloud/lib/mutelist/mutelist.py @@ -0,0 +1,82 @@ +""" +Alibaba Cloud Provider Mutelist + +This module implements the mutelist functionality for suppressing findings +in Alibaba Cloud audits. +""" + +from prowler.lib.mutelist.mutelist import Mutelist + + +class AlibabaCloudMutelist(Mutelist): + """ + AlibabaCloudMutelist handles finding suppression for Alibaba Cloud resources + + This class extends the base Mutelist class to provide Alibaba Cloud-specific + mutelist functionality, allowing users to suppress specific findings based on + resource identifiers, regions, checks, or other criteria. + + Example mutelist entry: + { + "Accounts": ["1234567890"], + "Checks": { + "ecs_*": { + "Regions": ["cn-hangzhou", "cn-shanghai"], + "Resources": ["i-abc123", "i-def456"] + } + } + } + """ + + def __init__( + self, + mutelist_path: str = None, + mutelist_content: dict = None, + provider: str = "alibabacloud", + identity: dict = None, + ): + """ + Initialize Alibaba Cloud mutelist + + Args: + mutelist_path: Path to the mutelist file (YAML or JSON) + mutelist_content: Mutelist content as a dictionary + provider: Provider name (default: "alibabacloud") + identity: Alibaba Cloud identity information + """ + super().__init__( + mutelist_path=mutelist_path, + mutelist_content=mutelist_content, + ) + self.identity = identity + self.provider = provider + + def is_finding_muted( + self, + finding, + account_id: str = None, + region: str = None, + check_id: str = None, + resource_id: str = None, + ) -> bool: + """ + Check if a finding should be muted based on mutelist rules + + Args: + finding: The finding object to check + account_id: Alibaba Cloud account ID + region: Alibaba Cloud region ID + check_id: Check identifier + resource_id: Resource identifier + + Returns: + bool: True if the finding is muted, False otherwise + """ + # Use the parent class implementation which handles the core logic + return super().is_muted( + account_uid=account_id or getattr(finding, "account_uid", None), + region=region or getattr(finding, "region", None), + check_id=check_id or getattr(finding, "check_metadata", {}).get("CheckID"), + resource_id=resource_id or getattr(finding, "resource_uid", None), + finding_tags=getattr(finding, "resource_tags", []), + ) diff --git a/prowler/providers/alibabacloud/lib/service/__init__.py b/prowler/providers/alibabacloud/lib/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/lib/service/service.py b/prowler/providers/alibabacloud/lib/service/service.py new file mode 100644 index 0000000000..1ae17c5074 --- /dev/null +++ b/prowler/providers/alibabacloud/lib/service/service.py @@ -0,0 +1,148 @@ +""" +Alibaba Cloud Service Base Class + +This module provides the base class for all Alibaba Cloud service implementations. +""" + +import threading +from typing import Any, Dict, List + +from prowler.lib.logger import logger + + +class AlibabaCloudService: + """ + Base class for Alibaba Cloud service implementations + + This class provides common functionality for all Alibaba Cloud services, including: + - Regional client management + - Multi-threading support for API calls + - Error handling patterns + - Resource auditing metadata + + Attributes: + provider: The Alibaba Cloud provider instance + service: Service name (e.g., "ecs", "oss", "ram") + account_id: Alibaba Cloud account ID + regions: List of regions to audit + audit_config: Audit configuration dictionary + regional_clients: Dictionary of regional SDK clients + """ + + def __init__(self, service: str, provider): + """ + Initialize the Alibaba Cloud service + + Args: + service: Service identifier (e.g., "ecs", "oss") + provider: AlibabaCloudProvider instance + """ + self.provider = provider + self.service = service + self.account_id = provider.identity.account_id + self.regions = provider._regions + self.audit_config = provider.audit_config + self.regional_clients = {} + + logger.info(f"Initializing Alibaba Cloud {service.upper()} service") + + def __threading_call__(self, call, iterator): + """ + Execute function calls in parallel using threading + + This method is used to parallelize API calls across regions or resources + to improve audit performance. + + Args: + call: Function to execute + iterator: Iterable of arguments to pass to the function + + Example: + self.__threading_call__(self._describe_instances, self.regions) + """ + threads = [] + for item in iterator: + thread = threading.Thread(target=call, args=(item,)) + threads.append(thread) + thread.start() + + # Wait for all threads to complete + for thread in threads: + thread.join() + + def _create_regional_client(self, region: str, endpoint_override: str = None): + """ + Create a regional Alibaba Cloud SDK client + + This method should be overridden by service implementations to create + service-specific clients. + + Args: + region: Region identifier + endpoint_override: Optional endpoint override URL + + Returns: + SDK client instance for the specified region + """ + raise NotImplementedError( + f"Service {self.service} must implement _create_regional_client()" + ) + + def _list_resources(self): + """ + List all resources for this service + + This method should be overridden by service implementations to list + service-specific resources. + """ + raise NotImplementedError( + f"Service {self.service} must implement _list_resources()" + ) + + def _get_resource_details(self, resource): + """ + Get detailed information about a resource + + This method can be overridden by service implementations to fetch + additional resource details. + + Args: + resource: Resource identifier or object + """ + pass + + def _handle_api_error(self, error: Exception, operation: str, region: str = None): + """ + Handle Alibaba Cloud API errors with consistent logging + + Args: + error: The exception that occurred + operation: The API operation that failed + region: The region where the error occurred (if applicable) + """ + region_info = f" in region {region}" if region else "" + logger.warning( + f"{self.service.upper()} {operation} failed{region_info}: {str(error)}" + ) + + def generate_resource_arn( + self, resource_type: str, resource_id: str, region: str = "" + ) -> str: + """ + Generate Alibaba Cloud Resource Name (ARN) in ACS format + + Format: acs:{service}:{region}:{account-id}:{resource-type}/{resource-id} + + Args: + resource_type: Type of resource (e.g., "instance", "bucket") + resource_id: Resource identifier + region: Region identifier (optional for global resources) + + Returns: + str: Formatted ARN string + + Example: + arn = self.generate_resource_arn("instance", "i-abc123", "cn-hangzhou") + # Returns: "acs:ecs:cn-hangzhou:123456789:instance/i-abc123" + """ + return f"acs:{self.service}:{region}:{self.account_id}:{resource_type}/{resource_id}" diff --git a/prowler/providers/alibabacloud/models.py b/prowler/providers/alibabacloud/models.py new file mode 100644 index 0000000000..c67a26b853 --- /dev/null +++ b/prowler/providers/alibabacloud/models.py @@ -0,0 +1,129 @@ +""" +Alibaba Cloud Provider Models + +This module contains data models for the Alibaba Cloud provider. +""" + +from argparse import Namespace +from dataclasses import dataclass +from typing import Optional + +from prowler.providers.common.models import ProviderOutputOptions + + +@dataclass +class AlibabaCloudIdentityInfo: + """ + AlibabaCloudIdentityInfo contains the Alibaba Cloud identity information + + Attributes: + account_id: Alibaba Cloud account ID + account_arn: Alibaba Cloud account ARN + user_id: RAM user ID (optional) + user_name: RAM user name (optional) + account_name: Account alias/name (optional) + """ + account_id: str + account_arn: str + user_id: Optional[str] = None + user_name: Optional[str] = None + account_name: Optional[str] = None + + +@dataclass +class AlibabaCloudRegion: + """ + AlibabaCloudRegion contains region information + + Attributes: + region_id: Region identifier (e.g., "cn-hangzhou") + local_name: Localized region name + region_endpoint: Region endpoint URL + """ + region_id: str + local_name: str + region_endpoint: Optional[str] = None + + +@dataclass +class AlibabaCloudCredentials: + """ + AlibabaCloudCredentials contains authentication credentials + + Attributes: + access_key_id: AccessKey ID + access_key_secret: AccessKey Secret + security_token: STS security token (optional) + expiration: Token expiration timestamp (optional) + """ + access_key_id: str + access_key_secret: str + security_token: Optional[str] = None + expiration: Optional[str] = None + + +@dataclass +class AlibabaCloudAssumeRoleInfo: + """ + AlibabaCloudAssumeRoleInfo contains RAM role assumption information + + Attributes: + role_arn: RAM role ARN to assume + role_session_name: Session name for the assumed role + external_id: External ID for role assumption (optional) + session_duration: Duration in seconds (900-43200, default 3600) + """ + role_arn: str + role_session_name: str + external_id: Optional[str] = None + session_duration: int = 3600 + + +@dataclass +class AlibabaCloudSession: + """ + AlibabaCloudSession contains the session configuration + + Attributes: + credentials: Alibaba Cloud credentials + region_id: Default region for the session + """ + credentials: AlibabaCloudCredentials + region_id: str = "cn-hangzhou" + + +class AlibabaCloudOutputOptions(ProviderOutputOptions): + """ + AlibabaCloudOutputOptions contains the output configuration for Alibaba Cloud + + This class extends ProviderOutputOptions to provide Alibaba Cloud-specific + output filename generation based on the account ID. + """ + + def __init__(self, arguments: Namespace, bulk_checks_metadata: dict, identity: AlibabaCloudIdentityInfo): + """ + Initialize Alibaba Cloud output options + + Args: + arguments: Command-line arguments + bulk_checks_metadata: Metadata for all checks + identity: Alibaba Cloud identity information + """ + # Call parent class init + super().__init__(arguments, bulk_checks_metadata) + + # Import here to avoid circular dependency + from prowler.config.config import output_file_timestamp + + # Check if custom output filename was provided + if ( + not hasattr(arguments, "output_filename") + or arguments.output_filename is None + ): + # Use account ID for output filename + account_identifier = identity.account_id + self.output_filename = ( + f"prowler-output-{account_identifier}-{output_file_timestamp}" + ) + else: + self.output_filename = arguments.output_filename diff --git a/prowler/providers/alibabacloud/services/__init__.py b/prowler/providers/alibabacloud/services/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/services/ack/__init__.py b/prowler/providers/alibabacloud/services/ack/__init__.py new file mode 100644 index 0000000000..35c4b59606 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud ACK (Container Service for Kubernetes) module""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_client.py b/prowler/providers/alibabacloud/services/ack/ack_client.py new file mode 100644 index 0000000000..f95d463157 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud ACK Client Singleton""" + +from prowler.providers.alibabacloud.services.ack.ack_service import ACK +from prowler.providers.common.provider import Provider + +ack_client = ACK(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py new file mode 100644 index 0000000000..db396feb5b --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py @@ -0,0 +1 @@ +"""ACK Audit Logging Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.metadata.json new file mode 100644 index 0000000000..7c415ca9b5 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_audit_log", + "CheckTitle": "Check ACK Audit Logging", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Cluster", + "Description": "Checks ACK Audit Logging.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.py new file mode 100644 index 0000000000..8bea289bbd --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_audit_log + +Ensures that ACK clusters have audit logging enabled with Simple Log Service (SLS). +Audit logs are essential for security monitoring, troubleshooting, and compliance. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_audit_log(Check): + """Check if ACK clusters have audit logging enabled""" + + def execute(self): + """Execute the ack_cluster_audit_log check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.audit_log_enabled: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has audit logging enabled with SLS." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have audit logging enabled. Enable audit logging with Simple Log Service for security monitoring and compliance." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py new file mode 100644 index 0000000000..9cca0564db --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py @@ -0,0 +1 @@ +"""ACK Encryption Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.metadata.json new file mode 100644 index 0000000000..8cddb56a49 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_encryption", + "CheckTitle": "Check ACK Encryption", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Cluster", + "Description": "Checks ACK Encryption.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.py new file mode 100644 index 0000000000..e178ccad14 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_encryption + +Ensures that ACK clusters have encryption enabled for data at rest. +Encryption protects sensitive Kubernetes secrets and configuration data. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_encryption(Check): + """Check if ACK clusters have encryption enabled""" + + def execute(self): + """Execute the ack_cluster_encryption check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.encryption_enabled: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has encryption enabled for data at rest." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have encryption enabled. Enable encryption to protect Kubernetes secrets and configuration data." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py new file mode 100644 index 0000000000..890b643327 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py @@ -0,0 +1 @@ +"""ACK Network Policy Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.metadata.json new file mode 100644 index 0000000000..207045c522 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_network_policy", + "CheckTitle": "Check ACK Network Policy", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Cluster", + "Description": "Checks ACK Network Policy.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.py new file mode 100644 index 0000000000..ecd182b7db --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_network_policy + +Ensures that ACK clusters have network policy support enabled. +Network policies control traffic between pods and enhance security isolation. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_network_policy(Check): + """Check if ACK clusters have network policy support enabled""" + + def execute(self): + """Execute the ack_cluster_network_policy check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.network_policy_enabled: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has network policy support enabled." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have network policy support enabled. Enable network policies to control traffic between pods." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py new file mode 100644 index 0000000000..224215da5e --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py @@ -0,0 +1 @@ +"""ACK Private Zone Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.metadata.json new file mode 100644 index 0000000000..6ed5baba48 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_private_zone", + "CheckTitle": "Check ACK Private Zone", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "Cluster", + "Description": "Checks ACK Private Zone.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.py new file mode 100644 index 0000000000..56fcc05327 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_private_zone + +Ensures that ACK clusters have PrivateZone enabled for private DNS resolution. +PrivateZone provides DNS resolution for services within the VPC without exposing to public internet. + +Risk Level: LOW +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_private_zone(Check): + """Check if ACK clusters have PrivateZone enabled""" + + def execute(self): + """Execute the ack_cluster_private_zone check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.private_zone_enabled: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has PrivateZone enabled for private DNS resolution." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have PrivateZone enabled. Consider enabling PrivateZone for enhanced DNS privacy." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py new file mode 100644 index 0000000000..e37d1d03e6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py @@ -0,0 +1 @@ +"""ACK Public Access Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.metadata.json new file mode 100644 index 0000000000..b3333dc45b --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_public_access", + "CheckTitle": "Check ACK Public Access", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Cluster", + "Description": "Checks ACK Public Access.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.py new file mode 100644 index 0000000000..45a03fe204 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_public_access + +Ensures that ACK cluster API servers are not publicly accessible from the internet. +Public access to Kubernetes API servers increases the attack surface. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_public_access(Check): + """Check if ACK clusters have public access disabled""" + + def execute(self): + """Execute the ack_cluster_public_access check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if not cluster.public_access: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} API server is not publicly accessible." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} API server is publicly accessible. Restrict access to private networks only." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py new file mode 100644 index 0000000000..05e73e7c3a --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py @@ -0,0 +1 @@ +"""ACK RBAC Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.metadata.json new file mode 100644 index 0000000000..1f42b124e6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_rbac", + "CheckTitle": "Check ACK RBAC", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Cluster", + "Description": "Checks ACK RBAC.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.py new file mode 100644 index 0000000000..a788049b15 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_rbac + +Ensures that ACK clusters have RBAC (Role-Based Access Control) enabled. +RBAC controls access to cluster resources based on user roles and permissions. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_rbac(Check): + """Check if ACK clusters have RBAC enabled""" + + def execute(self): + """Execute the ack_cluster_rbac check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.rbac_enabled: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has RBAC enabled for access control." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have RBAC enabled. Enable RBAC to control access to cluster resources based on user roles." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py new file mode 100644 index 0000000000..0f0c8e7c46 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py @@ -0,0 +1 @@ +"""ACK Security Group Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.metadata.json new file mode 100644 index 0000000000..e566a4524a --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_security_group", + "CheckTitle": "Check ACK Security Group", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Cluster", + "Description": "Checks ACK Security Group.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.py new file mode 100644 index 0000000000..737d0b71fc --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_security_group + +Ensures that ACK clusters have security groups configured. +Security groups act as virtual firewalls to control inbound and outbound traffic. + +Risk Level: HIGH +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_security_group(Check): + """Check if ACK clusters have security groups configured""" + + def execute(self): + """Execute the ack_cluster_security_group check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.security_group_id: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} has security group {cluster.security_group_id} configured." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} does not have a security group configured. Configure a security group to control network traffic." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py new file mode 100644 index 0000000000..23f51d6beb --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py @@ -0,0 +1 @@ +"""ACK VPC Check""" diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.metadata.json b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.metadata.json new file mode 100644 index 0000000000..ae0de3447f --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ack_cluster_vpc", + "CheckTitle": "Check ACK VPC", + "CheckType": [], + "ServiceName": "ack", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Cluster", + "Description": "Checks ACK VPC.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.py b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.py new file mode 100644 index 0000000000..a13e305ea1 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc.py @@ -0,0 +1,38 @@ +""" +Check: ack_cluster_vpc + +Ensures that ACK clusters are deployed within a VPC (Virtual Private Cloud). +Running clusters in a VPC provides network isolation and enhanced security controls. + +Risk Level: HIGH +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ack.ack_client import ack_client + + +class ack_cluster_vpc(Check): + """Check if ACK clusters are deployed in a VPC""" + + def execute(self): + """Execute the ack_cluster_vpc check""" + findings = [] + + for cluster_arn, cluster in ack_client.clusters.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=cluster) + report.account_uid = ack_client.account_id + report.region = cluster.region + report.resource_id = cluster.cluster_id + report.resource_arn = cluster.arn + + if cluster.vpc_id: + report.status = "PASS" + report.status_extended = f"ACK cluster {cluster.cluster_name} is deployed in VPC {cluster.vpc_id}." + else: + report.status = "FAIL" + report.status_extended = f"ACK cluster {cluster.cluster_name} is not deployed in a VPC. Deploy clusters in VPC for network isolation and enhanced security." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ack/ack_service.py b/prowler/providers/alibabacloud/services/ack/ack_service.py new file mode 100644 index 0000000000..d161214f52 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ack/ack_service.py @@ -0,0 +1,56 @@ +"""Alibaba Cloud ACK Service""" + +from dataclasses import dataclass +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class Cluster: + """ACK Cluster""" + cluster_id: str + cluster_name: str + arn: str + region: str + cluster_type: str = "Kubernetes" + state: str = "running" + public_access: bool = True # Will trigger check + private_zone_enabled: bool = False + network_policy_enabled: bool = False # Will trigger check + rbac_enabled: bool = True + encryption_enabled: bool = False # Will trigger check + audit_log_enabled: bool = False # Will trigger check + security_group_id: str = "" + vpc_id: str = "" + master_url: str = "" + + def __post_init__(self): + pass + + +class ACK(AlibabaCloudService): + def __init__(self, provider): + super().__init__("ack", provider) + self.clusters = {} + logger.info("Collecting ACK clusters...") + self._describe_clusters() + logger.info(f"ACK service initialized - Clusters: {len(self.clusters)}") + + def _describe_clusters(self): + for region in self.regions: + try: + cluster_id = f"c-demo-{region}" + arn = self.generate_resource_arn("cluster", cluster_id, region) + cluster = Cluster( + cluster_id=cluster_id, + cluster_name=f"demo-cluster-{region}", + arn=arn, + region=region, + public_access=True, + network_policy_enabled=False, + encryption_enabled=False, + audit_log_enabled=False + ) + self.clusters[arn] = cluster + except Exception as error: + self._handle_api_error(error, "DescribeClusters", region) diff --git a/prowler/providers/alibabacloud/services/actiontrail/__init__.py b/prowler/providers/alibabacloud/services/actiontrail/__init__.py new file mode 100644 index 0000000000..2150bde140 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud ActionTrail module""" diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_client.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_client.py new file mode 100644 index 0000000000..7208b63dd5 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud ActionTrail Client Singleton""" + +from prowler.providers.alibabacloud.services.actiontrail.actiontrail_service import ActionTrail +from prowler.providers.common.provider import Provider + +actiontrail_client = ActionTrail(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_service.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_service.py new file mode 100644 index 0000000000..7c10d4d3bc --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_service.py @@ -0,0 +1,77 @@ +""" +Alibaba Cloud ActionTrail Service + +This module provides the service class for Alibaba Cloud ActionTrail. +""" + +from dataclasses import dataclass +from typing import Optional + +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class Trail: + """ActionTrail Trail""" + name: str + arn: str + region: str + status: str = "Disabled" # Will trigger check + oss_bucket_name: str = "" + oss_key_prefix: str = "" + sls_project_arn: str = "" + sls_write_role_arn: str = "" + event_rw: str = "Write" # Should be "All" + trail_region: str = "All" + is_organization_trail: bool = False + mns_topic_arn: str = "" + + def __post_init__(self): + pass + + +class ActionTrail(AlibabaCloudService): + """ + Alibaba Cloud ActionTrail service class + + Handles collection of ActionTrail resources including trails and their configurations. + """ + + def __init__(self, provider): + """Initialize ActionTrail service""" + super().__init__("actiontrail", provider) + + self.trails = {} + + logger.info("Collecting ActionTrail trails...") + self._describe_trails() + + logger.info( + f"ActionTrail service initialized - Trails: {len(self.trails)}" + ) + + def _describe_trails(self): + """Describe all ActionTrail trails""" + # ActionTrail is a global service, but we'll check it once + try: + # TODO: Implement actual SDK call + # Placeholder: Create sample trail for demonstration + trail_name = "prowler-demo-trail" + arn = self.generate_resource_arn("trail", trail_name, "") + + trail = Trail( + name=trail_name, + arn=arn, + region="global", + status="Disabled", # Should be "Enabled" + oss_bucket_name="audit-logs-bucket", + event_rw="Write", # Should be "All" to log both read and write + trail_region="All", + is_organization_trail=False + ) + + self.trails[arn] = trail + + except Exception as error: + self._handle_api_error(error, "DescribeTrails", "global") diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py new file mode 100644 index 0000000000..b15e3c668d --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py @@ -0,0 +1 @@ +"""ActionTrail Trail Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.metadata.json b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.metadata.json new file mode 100644 index 0000000000..c7c7434629 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "actiontrail_trail_enabled", + "CheckTitle": "Ensure at least one ActionTrail trail is enabled", + "CheckType": [], + "ServiceName": "actiontrail", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Trail", + "Description": "Ensures that at least one ActionTrail trail is enabled to log API activity for security auditing. ActionTrail records API calls and events for compliance, security analysis, and troubleshooting.", + "Risk": "Without ActionTrail enabled, there is no audit log of API activity, making it impossible to track changes, detect unauthorized access, or investigate security incidents. This can lead to compliance violations and delayed incident response.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/ActionTrail/trail-enabled.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable at least one ActionTrail trail. Go to ActionTrail Console and create/enable a trail to log API activity across all regions.", + "Url": "https://www.alibabacloud.com/help/en/actiontrail/latest/create-a-trail-to-deliver-events-to-oss" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.py new file mode 100644 index 0000000000..6a92c45d82 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled.py @@ -0,0 +1,47 @@ +""" +Check: actiontrail_trail_enabled + +Ensures that at least one ActionTrail trail is enabled to log API activity for security auditing. +ActionTrail records API calls and events for compliance, security analysis, and troubleshooting. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.actiontrail.actiontrail_client import actiontrail_client + + +class actiontrail_trail_enabled(Check): + """Check if at least one ActionTrail trail is enabled""" + + def execute(self): + """Execute the actiontrail_trail_enabled check""" + findings = [] + + # Check if there's at least one enabled trail + enabled_trails = [trail for trail in actiontrail_client.trails.values() if trail.status == "Enabled"] + + # Create a report for the account + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'actiontrail-configuration', + 'name': 'ActionTrail Configuration', + 'arn': f"acs:actiontrail::{actiontrail_client.account_id}:configuration", + 'region': 'global' + })()) + + report.account_uid = actiontrail_client.account_id + report.region = "global" + report.resource_id = "actiontrail-configuration" + report.resource_arn = f"acs:actiontrail::{actiontrail_client.account_id}:configuration" + + if len(enabled_trails) > 0: + trail_names = [trail.name for trail in enabled_trails] + report.status = "PASS" + report.status_extended = f"ActionTrail has {len(enabled_trails)} enabled trail(s): {', '.join(trail_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled ActionTrail trails found. Enable at least one trail to log API activity for security auditing and compliance." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py new file mode 100644 index 0000000000..322f5a2f54 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py @@ -0,0 +1 @@ +"""ActionTrail Trail Logs All Events Check""" diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.metadata.json b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.metadata.json new file mode 100644 index 0000000000..5a80115b68 --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "actiontrail_trail_logs_all_events", + "CheckTitle": "Ensure ActionTrail trails log all events (read and write)", + "CheckType": [], + "ServiceName": "actiontrail", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Trail", + "Description": "Ensures that ActionTrail trails are configured to log both read and write events. Logging all events provides complete audit coverage for security analysis and compliance.", + "Risk": "Logging only write events means read-only API calls are not recorded, potentially missing important security events such as unauthorized data access attempts or reconnaissance activities.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/ActionTrail/trail-log-all-events.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update ActionTrail trails to log all events. Go to ActionTrail Console, select the trail, and configure it to log both read and write events.", + "Url": "https://www.alibabacloud.com/help/en/actiontrail/latest/create-a-trail-to-deliver-events-to-oss" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.py b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.py new file mode 100644 index 0000000000..8a79bc4e7e --- /dev/null +++ b/prowler/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events.py @@ -0,0 +1,38 @@ +""" +Check: actiontrail_trail_logs_all_events + +Ensures that ActionTrail trails are configured to log both read and write events. +Logging all events provides complete audit coverage for security analysis and compliance. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.actiontrail.actiontrail_client import actiontrail_client + + +class actiontrail_trail_logs_all_events(Check): + """Check if ActionTrail trails log all events (read and write)""" + + def execute(self): + """Execute the actiontrail_trail_logs_all_events check""" + findings = [] + + for trail_arn, trail in actiontrail_client.trails.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=trail) + report.account_uid = actiontrail_client.account_id + report.region = trail.region + report.resource_id = trail.name + report.resource_arn = trail.arn + + if trail.event_rw == "All": + report.status = "PASS" + report.status_extended = f"ActionTrail trail {trail.name} logs all events (read and write)." + else: + report.status = "FAIL" + report.status_extended = f"ActionTrail trail {trail.name} only logs {trail.event_rw} events. Configure the trail to log all events (read and write) for complete audit coverage." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ecs/__init__.py b/prowler/providers/alibabacloud/services/ecs/__init__.py new file mode 100644 index 0000000000..1805e5025c --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud ECS (Elastic Compute Service) module""" diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_client.py b/prowler/providers/alibabacloud/services/ecs/ecs_client.py new file mode 100644 index 0000000000..d66b5e031f --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_client.py @@ -0,0 +1,11 @@ +""" +Alibaba Cloud ECS Client Singleton + +This module provides the singleton ECS client instance. +""" + +from prowler.providers.alibabacloud.services.ecs.ecs_service import ECS +from prowler.providers.common.provider import Provider + +# Initialize ECS client singleton +ecs_client = ECS(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/__init__.py b/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.metadata.json b/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.metadata.json new file mode 100644 index 0000000000..5f493ea0c6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.metadata.json @@ -0,0 +1,37 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ecs_disk_encryption_enabled", + "CheckTitle": "Ensure ECS Disk Encryption is Enabled", + "CheckType": [ + "Security", + "Encryption" + ], + "ServiceName": "ecs", + "SubServiceName": "disk", + "ResourceIdTemplate": "arn:acs:ecs:region:account-id:disk/disk-id", + "Severity": "medium", + "ResourceType": "AlibabaCloud::ECS::Disk", + "Description": "Ensure that all ECS disks (system disks and data disks) are encrypted to protect data at rest. Disk encryption provides an additional layer of security by encrypting data stored on ECS instances using Alibaba Cloud KMS.", + "Risk": "Unencrypted disks can expose sensitive data if the physical storage media is compromised, if disk snapshots are inadvertently shared, or if unauthorized users gain access to the disk. Without encryption, data at rest is vulnerable to unauthorized access.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/ECS/disk-encryption.html", + "Remediation": { + "Code": { + "CLI": "# Note: Encryption must be enabled when creating a disk. Existing disks cannot be encrypted in-place.\n# Create a snapshot of the unencrypted disk, then create a new encrypted disk from the snapshot:\naliyun ecs CreateSnapshot --DiskId --SnapshotName encrypted-snapshot\naliyun ecs CreateDisk --SnapshotId --Encrypted true --KMSKeyId ", + "NativeIaC": "", + "Other": "For existing disks, you must create a snapshot, create a new encrypted disk from the snapshot, detach the old disk, attach the new encrypted disk, and then delete the old disk.", + "Terraform": "resource \"alicloud_disk\" \"encrypted_disk\" {\n disk_name = \"encrypted-disk\"\n size = 100\n category = \"cloud_essd\"\n encrypted = true\n kms_key_id = var.kms_key_id\n zone_id = \"cn-hangzhou-h\"\n}" + }, + "Recommendation": { + "Text": "Enable disk encryption for all new ECS disks. For existing unencrypted disks, create encrypted copies using snapshots and KMS. Use customer-managed KMS keys for enhanced control over encryption keys. Regularly rotate encryption keys and audit key usage.", + "Url": "https://www.alibabacloud.com/help/en/ecs/user-guide/encryption-overview" + } + }, + "Categories": [ + "encryption", + "data-protection" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "ECS disk encryption cannot be enabled on existing disks. You must create new encrypted disks or create encrypted copies from snapshots. Consider enabling default encryption at the account level to ensure all new disks are automatically encrypted.", + "Compliance": [] +} diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.py b/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.py new file mode 100644 index 0000000000..eca871a48b --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled.py @@ -0,0 +1,49 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ecs.ecs_client import ecs_client + + +class ecs_disk_encryption_enabled(Check): + """ + Check if ECS disks are encrypted + + This check ensures that all ECS disks (both system and data disks) are + encrypted to protect data at rest. Encryption helps prevent unauthorized + access to disk data. + + Risk: Unencrypted disks can expose sensitive data if physical media is + compromised or if snapshots are inadvertently shared. + + Recommendation: Enable disk encryption for all ECS disks using Alibaba + Cloud KMS (Key Management Service). + """ + + def execute(self): + """Execute the check""" + findings = [] + + # Iterate through all ECS disks + for disk_arn, disk in ecs_client.disks.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=disk) + report.account_uid = ecs_client.account_id + report.region = disk.region + report.resource_id = disk.id + report.resource_arn = disk.arn + + if disk.encrypted: + report.status = "PASS" + report.status_extended = ( + f"ECS disk {disk.name} ({disk.id}) is encrypted" + ) + if disk.kms_key_id: + report.status_extended += f" using KMS key {disk.kms_key_id}" + report.status_extended += "." + else: + report.status = "FAIL" + report.status_extended = ( + f"ECS disk {disk.name} ({disk.id}) is not encrypted. " + f"Enable encryption to protect data at rest." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/__init__.py b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/__init__.py new file mode 100644 index 0000000000..9080c49139 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/__init__.py @@ -0,0 +1 @@ +"""ECS Instance Public IP Check""" diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.metadata.json b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.metadata.json new file mode 100644 index 0000000000..ea830d45f2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ecs_instance_public_ip", + "CheckTitle": "Ensure ECS instances do not have unnecessary public IPs", + "CheckType": [], + "ServiceName": "ecs", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Instance", + "Description": "Ensures ECS instances do not have unnecessary public IP addresses.", + "Risk": "Public IP addresses increase attack surface.", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "Use EIP or NAT Gateway instead.", "Url": ""}}, + "Categories": ["internet-exposed"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.py b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.py new file mode 100644 index 0000000000..a74cdf8642 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip.py @@ -0,0 +1,21 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ecs.ecs_client import ecs_client + +class ecs_instance_public_ip(Check): + def execute(self): + findings = [] + for instance_arn, instance in ecs_client.instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=instance) + report.account_uid = ecs_client.account_id + report.region = instance.region + report.resource_id = instance.id + report.resource_arn = instance.arn + + if not instance.public_ip: + report.status = "PASS" + report.status_extended = f"ECS instance {instance.name} does not have a public IP address." + else: + report.status = "FAIL" + report.status_extended = f"ECS instance {instance.name} has public IP {instance.public_ip}. Consider using EIP or NAT Gateway instead." + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/__init__.py b/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.metadata.json b/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.metadata.json new file mode 100644 index 0000000000..5e60120ad6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.metadata.json @@ -0,0 +1,37 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ecs_instance_ssh_access_restricted", + "CheckTitle": "Check for Unrestricted SSH Access", + "CheckType": [ + "Security", + "Network" + ], + "ServiceName": "ecs", + "SubServiceName": "security_group", + "ResourceIdTemplate": "arn:acs:ecs:region:account-id:security-group/sg-id", + "Severity": "high", + "ResourceType": "AlibabaCloud::ECS::SecurityGroup", + "Description": "Ensure ECS security groups do not allow unrestricted SSH access (port 22) from the internet (0.0.0.0/0). Unrestricted SSH access increases the risk of unauthorized access, brute force attacks, and potential security breaches.", + "Risk": "Allowing unrestricted SSH access from the internet can expose instances to brute force attacks, unauthorized access attempts, and potential compromise. Attackers can scan for open SSH ports and attempt to gain unauthorized access to instances.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/ECS/unrestricted-ssh-access.html", + "Remediation": { + "Code": { + "CLI": "aliyun ecs ModifySecurityGroupRule --SecurityGroupId --IpProtocol tcp --PortRange 22/22 --SourceCidrIp /32", + "NativeIaC": "", + "Other": "", + "Terraform": "resource \"alicloud_security_group_rule\" \"allow_ssh_from_specific_ip\" {\n type = \"ingress\"\n ip_protocol = \"tcp\"\n port_range = \"22/22\"\n security_group_id = alicloud_security_group.group.id\n cidr_ip = \"203.0.113.0/24\"\n}" + }, + "Recommendation": { + "Text": "Restrict SSH access to specific trusted IP addresses or IP ranges. Implement a bastion host or VPN for secure remote access. Consider using Alibaba Cloud's Session Manager for instance access without opening SSH ports.", + "Url": "https://www.alibabacloud.com/help/en/ecs/user-guide/security-groups-overview" + } + }, + "Categories": [ + "internet-exposed", + "encryption" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check examines security group rules to identify unrestricted SSH access. It is recommended to use the principle of least privilege and only allow SSH access from known, trusted IP addresses.", + "Compliance": [] +} diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.py b/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.py new file mode 100644 index 0000000000..8bc188e3a2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted.py @@ -0,0 +1,59 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ecs.ecs_client import ecs_client + + +class ecs_instance_ssh_access_restricted(Check): + """ + Check if ECS security groups restrict SSH access from the internet + + This check ensures that security groups associated with ECS instances + do not allow unrestricted SSH access (0.0.0.0/0) on port 22. + + Risk: Unrestricted SSH access can lead to unauthorized access attempts + and potential security breaches. + + Recommendation: Restrict SSH access to specific IP addresses or ranges. + """ + + def execute(self): + """Execute the check""" + findings = [] + + # Iterate through all security groups + for sg_arn, security_group in ecs_client.security_groups.items(): + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), resource=security_group + ) + report.account_uid = ecs_client.account_id + report.region = security_group.region + report.resource_id = security_group.id + report.resource_arn = security_group.arn + + # Check for unrestricted SSH access + has_unrestricted_ssh = False + for rule in security_group.rules: + if ( + rule.get("direction") == "ingress" + and rule.get("protocol") == "tcp" + and "22" in rule.get("port_range", "") + and rule.get("source") == "0.0.0.0/0" + ): + has_unrestricted_ssh = True + break + + if has_unrestricted_ssh: + report.status = "FAIL" + report.status_extended = ( + f"Security group {security_group.name} ({security_group.id}) " + f"allows unrestricted SSH access from the internet (0.0.0.0/0)." + ) + else: + report.status = "PASS" + report.status_extended = ( + f"Security group {security_group.name} ({security_group.id}) " + f"does not allow unrestricted SSH access from the internet." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ecs/ecs_service.py b/prowler/providers/alibabacloud/services/ecs/ecs_service.py new file mode 100644 index 0000000000..4c2627a75b --- /dev/null +++ b/prowler/providers/alibabacloud/services/ecs/ecs_service.py @@ -0,0 +1,293 @@ +""" +Alibaba Cloud ECS Service + +This module provides the service class for Alibaba Cloud Elastic Compute Service (ECS). +""" + +from dataclasses import dataclass +from typing import Optional + +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class Instance: + """ + Represents an Alibaba Cloud ECS instance + + Attributes: + id: Instance ID + name: Instance name + arn: Instance ARN + region: Region where the instance is located + status: Instance status (Running, Stopped, etc.) + instance_type: Instance type/specification + public_ip: Public IP address (if any) + private_ip: Private IP address + security_groups: List of security group IDs + vpc_id: VPC ID + zone_id: Availability zone ID + image_id: OS image ID + tags: Instance tags + created_time: Creation timestamp + expired_time: Expiration timestamp (for subscription instances) + """ + + id: str + name: str + arn: str + region: str + status: str = "" + instance_type: str = "" + public_ip: Optional[str] = None + private_ip: str = "" + security_groups: list = None + vpc_id: str = "" + zone_id: str = "" + image_id: str = "" + tags: dict = None + created_time: str = "" + expired_time: str = "" + + def __post_init__(self): + if self.security_groups is None: + self.security_groups = [] + if self.tags is None: + self.tags = {} + + +@dataclass +class Disk: + """ + Represents an Alibaba Cloud ECS disk + + Attributes: + id: Disk ID + name: Disk name + arn: Disk ARN + region: Region where the disk is located + disk_type: Type of disk (system, data) + category: Disk category (cloud_ssd, cloud_essd, etc.) + size: Disk size in GB + encrypted: Whether the disk is encrypted + kms_key_id: KMS key ID used for encryption (if encrypted) + status: Disk status (Available, In_use, etc.) + instance_id: Attached instance ID (if attached) + zone_id: Availability zone ID + tags: Disk tags + """ + + id: str + name: str + arn: str + region: str + disk_type: str = "" + category: str = "" + size: int = 0 + encrypted: bool = False + kms_key_id: Optional[str] = None + status: str = "" + instance_id: Optional[str] = None + zone_id: str = "" + tags: dict = None + + def __post_init__(self): + if self.tags is None: + self.tags = {} + + +@dataclass +class SecurityGroup: + """ + Represents an Alibaba Cloud security group + + Attributes: + id: Security group ID + name: Security group name + arn: Security group ARN + region: Region where the security group is located + vpc_id: VPC ID + description: Security group description + rules: List of security group rules + tags: Security group tags + """ + + id: str + name: str + arn: str + region: str + vpc_id: str = "" + description: str = "" + rules: list = None + tags: dict = None + + def __post_init__(self): + if self.rules is None: + self.rules = [] + if self.tags is None: + self.tags = {} + + +class ECS(AlibabaCloudService): + """ + Alibaba Cloud ECS service class + + This class handles the collection of ECS resources including instances, + disks, and security groups for auditing. + """ + + def __init__(self, provider): + """ + Initialize ECS service + + Args: + provider: AlibabaCloudProvider instance + """ + super().__init__("ecs", provider) + + # Initialize resource dictionaries + self.instances = {} + self.disks = {} + self.security_groups = {} + + # Collect ECS resources + logger.info("Collecting ECS instances...") + self._describe_instances() + + logger.info("Collecting ECS disks...") + self._describe_disks() + + logger.info("Collecting ECS security groups...") + self._describe_security_groups() + + logger.info( + f"ECS service initialized - Instances: {len(self.instances)}, " + f"Disks: {len(self.disks)}, Security Groups: {len(self.security_groups)}" + ) + + def _describe_instances(self): + """ + Describe ECS instances across all regions + + This method collects all ECS instances and their details. + """ + logger.info("Describing ECS instances across regions...") + + for region in self.regions: + try: + # TODO: Implement actual Alibaba Cloud SDK call + # from alibabacloud_ecs20140526.client import Client + # from alibabacloud_ecs20140526.models import DescribeInstancesRequest + # + # client = self._create_regional_client(region) + # request = DescribeInstancesRequest() + # response = client.describe_instances(request) + # + # for instance_data in response.body.instances.instance: + # instance = self._parse_instance(instance_data, region) + # self.instances[instance.arn] = instance + + # Placeholder: Create sample instance for demonstration + instance_id = f"i-{region}-sample123" + arn = self.generate_resource_arn("instance", instance_id, region) + + instance = Instance( + id=instance_id, + name=f"sample-instance-{region}", + arn=arn, + region=region, + status="Running", + instance_type="ecs.t6-c1m1.large", + public_ip="192.0.2.1", + private_ip="10.0.1.10", + security_groups=["sg-sample123"], + vpc_id="vpc-sample123", + zone_id=f"{region}-a", + ) + + self.instances[arn] = instance + logger.info(f"Found ECS instance: {instance_id} in {region}") + + except Exception as error: + self._handle_api_error(error, "DescribeInstances", region) + + def _describe_disks(self): + """ + Describe ECS disks across all regions + + This method collects all ECS disks and their encryption status. + """ + logger.info("Describing ECS disks across regions...") + + for region in self.regions: + try: + # TODO: Implement actual Alibaba Cloud SDK call + # Placeholder: Create sample disk for demonstration + disk_id = f"d-{region}-sample456" + arn = self.generate_resource_arn("disk", disk_id, region) + + disk = Disk( + id=disk_id, + name=f"sample-disk-{region}", + arn=arn, + region=region, + disk_type="data", + category="cloud_essd", + size=100, + encrypted=False, # This will be checked + status="In_use", + instance_id=f"i-{region}-sample123", + zone_id=f"{region}-a", + ) + + self.disks[arn] = disk + logger.info(f"Found ECS disk: {disk_id} in {region}") + + except Exception as error: + self._handle_api_error(error, "DescribeDisks", region) + + def _describe_security_groups(self): + """ + Describe security groups and their rules + + This method collects security groups and analyzes their rules. + """ + logger.info("Describing security groups across regions...") + + for region in self.regions: + try: + # TODO: Implement actual Alibaba Cloud SDK call + # Placeholder: Create sample security group + sg_id = f"sg-{region}-sample789" + arn = self.generate_resource_arn("security-group", sg_id, region) + + # Sample security group with unrestricted SSH access (for check demonstration) + security_group = SecurityGroup( + id=sg_id, + name=f"sample-sg-{region}", + arn=arn, + region=region, + vpc_id="vpc-sample123", + description="Sample security group", + rules=[ + { + "direction": "ingress", + "protocol": "tcp", + "port_range": "22/22", + "source": "0.0.0.0/0", # Unrestricted SSH! + }, + { + "direction": "ingress", + "protocol": "tcp", + "port_range": "443/443", + "source": "10.0.0.0/8", + }, + ], + ) + + self.security_groups[arn] = security_group + logger.info(f"Found security group: {sg_id} in {region}") + + except Exception as error: + self._handle_api_error(error, "DescribeSecurityGroups", region) diff --git a/prowler/providers/alibabacloud/services/oss/__init__.py b/prowler/providers/alibabacloud/services/oss/__init__.py new file mode 100644 index 0000000000..b0acece43a --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud OSS (Object Storage Service) module""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/__init__.py new file mode 100644 index 0000000000..db7b415790 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket CORS Not Overly Permissive Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.metadata.json new file mode 100644 index 0000000000..e8a4dfd01d --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_cors_not_overly_permissive", + "CheckTitle": "Ensure OSS bucket CORS rules are not overly permissive", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Bucket", + "Description": "Ensures that OSS bucket CORS (Cross-Origin Resource Sharing) rules are not overly permissive. Overly permissive CORS rules can allow unauthorized websites to access bucket resources.", + "Risk": "Overly permissive CORS rules allowing all origins (*) can enable malicious websites to access bucket resources, potentially leading to data leakage or unauthorized operations.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-cors.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update CORS rules to allow only specific trusted origins instead of '*'. Go to OSS Console > Buckets, select the bucket, and configure CORS rules with specific allowed origins.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/cors" + } + }, + "Categories": [ + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.py new file mode 100644 index 0000000000..2413cf7159 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive.py @@ -0,0 +1,50 @@ +""" +Check: oss_bucket_cors_not_overly_permissive + +Ensures that OSS bucket CORS (Cross-Origin Resource Sharing) rules are not overly permissive. +Overly permissive CORS rules can allow unauthorized websites to access bucket resources. + +Risk Level: MEDIUM +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_cors_not_overly_permissive(Check): + """Check if OSS bucket CORS rules are not overly permissive""" + + def execute(self): + """Execute the oss_bucket_cors_not_overly_permissive check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if not bucket.cors_rules or len(bucket.cors_rules) == 0: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} does not have CORS rules configured." + else: + # Check if any CORS rule allows all origins (*) + overly_permissive = False + for rule in bucket.cors_rules: + allowed_origins = rule.get("AllowedOrigin", []) + if "*" in allowed_origins: + overly_permissive = True + break + + if overly_permissive: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} has overly permissive CORS rules allowing all origins (*). Restrict CORS rules to specific trusted origins." + else: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has appropriately restrictive CORS rules." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/__init__.py new file mode 100644 index 0000000000..d65caf10cc --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Default Encryption KMS Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.metadata.json new file mode 100644 index 0000000000..02f8772c86 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_default_encryption_kms", + "CheckTitle": "Ensure OSS buckets use KMS for default encryption", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets use KMS (Key Management Service) for encryption instead of AES256. KMS provides better key management, rotation, and audit capabilities compared to AES256.", + "Risk": "Using AES256 encryption instead of KMS means missing out on centralized key management, automatic key rotation, and comprehensive audit logging capabilities.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-encryption-kms.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update OSS bucket encryption to use KMS instead of AES256. Go to OSS Console > Buckets, select the bucket, and configure server-side encryption with KMS.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/server-side-encryption" + } + }, + "Categories": [ + "encryption" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "KMS encryption may have additional costs compared to AES256." +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.py new file mode 100644 index 0000000000..912d5651a4 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms.py @@ -0,0 +1,42 @@ +""" +Check: oss_bucket_default_encryption_kms + +Ensures that OSS buckets use KMS (Key Management Service) for encryption instead of AES256. +KMS provides better key management, rotation, and audit capabilities compared to AES256. + +Risk Level: LOW +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_default_encryption_kms(Check): + """Check if OSS buckets use KMS for encryption""" + + def execute(self): + """Execute the oss_bucket_default_encryption_kms check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.encryption_enabled and bucket.encryption_algorithm: + if "KMS" in bucket.encryption_algorithm.upper(): + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} uses KMS for server-side encryption." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} uses {bucket.encryption_algorithm} for encryption. Consider using KMS for better key management and audit capabilities." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have encryption enabled. Enable KMS encryption for better security." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/__init__.py new file mode 100644 index 0000000000..c0afd2ae6b --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Encryption Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.metadata.json new file mode 100644 index 0000000000..2af0930409 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_encryption_enabled", + "CheckTitle": "Ensure OSS buckets have encryption enabled", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets have server-side encryption enabled to protect data at rest. Encryption protects sensitive data from unauthorized access.", + "Risk": "Unencrypted data at rest is vulnerable to unauthorized access if storage media is compromised. Encryption ensures data confidentiality even if physical access is obtained.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-encryption.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable server-side encryption for OSS buckets. Go to OSS Console > Buckets, select the bucket, and enable server-side encryption with AES256 or KMS.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/server-side-encryption" + } + }, + "Categories": [ + "encryption" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.py new file mode 100644 index 0000000000..dcb7d2fad8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_encryption_enabled + +Ensures that OSS buckets have server-side encryption enabled to protect data at rest. +Encryption protects sensitive data from unauthorized access. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_encryption_enabled(Check): + """Check if OSS buckets have encryption enabled""" + + def execute(self): + """Execute the oss_bucket_encryption_enabled check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.encryption_enabled: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has server-side encryption enabled with {bucket.encryption_algorithm}." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have server-side encryption enabled. Enable encryption to protect data at rest." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/__init__.py new file mode 100644 index 0000000000..b01a84f626 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Lifecycle Rules Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.metadata.json new file mode 100644 index 0000000000..e89288e2b5 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_lifecycle_rules", + "CheckTitle": "Ensure OSS buckets have lifecycle rules configured", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets have lifecycle rules configured to manage object lifecycle and optimize costs. Lifecycle rules automatically transition or delete objects based on age.", + "Risk": "Without lifecycle rules, old or unused objects remain in the bucket indefinitely, leading to unnecessary storage costs and difficulty managing data retention policies.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-lifecycle.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Configure lifecycle rules for OSS buckets. Go to OSS Console > Buckets, select the bucket, and create lifecycle rules to automatically transition or delete objects.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/lifecycle-rules" + } + }, + "Categories": [ + "trustworthy-ai" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.py new file mode 100644 index 0000000000..ddcfc3ed17 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_lifecycle_rules + +Ensures that OSS buckets have lifecycle rules configured to manage object lifecycle and optimize costs. +Lifecycle rules automatically transition or delete objects based on age. + +Risk Level: LOW +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_lifecycle_rules(Check): + """Check if OSS buckets have lifecycle rules configured""" + + def execute(self): + """Execute the oss_bucket_lifecycle_rules check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.lifecycle_rules and len(bucket.lifecycle_rules) > 0: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has {len(bucket.lifecycle_rules)} lifecycle rule(s) configured." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have lifecycle rules configured. Configure lifecycle rules to manage object lifecycle and optimize storage costs." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/__init__.py new file mode 100644 index 0000000000..513edfdb2a --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Logging Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.metadata.json new file mode 100644 index 0000000000..5098b7c3b8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_logging_enabled", + "CheckTitle": "Ensure OSS buckets have access logging enabled", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets have access logging enabled for audit and compliance purposes. Access logs provide detailed records of requests made to the bucket.", + "Risk": "Without access logging, it is difficult to track access patterns, detect unauthorized access attempts, or investigate security incidents. This can lead to compliance violations and delayed incident response.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-logging.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable access logging for OSS buckets. Go to OSS Console > Buckets, select the bucket, and configure logging with a target bucket for log storage.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/logging" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.py new file mode 100644 index 0000000000..1e7a9675e7 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_logging_enabled + +Ensures that OSS buckets have access logging enabled for audit and compliance purposes. +Access logs provide detailed records of requests made to the bucket. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_logging_enabled(Check): + """Check if OSS buckets have access logging enabled""" + + def execute(self): + """Execute the oss_bucket_logging_enabled check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.logging_enabled: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has access logging enabled (target: {bucket.access_logging_target})." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have access logging enabled. Enable logging for audit and compliance purposes." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/__init__.py new file mode 100644 index 0000000000..51fcf606d4 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Public Access Blocked Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.metadata.json new file mode 100644 index 0000000000..d9a196970b --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.metadata.json @@ -0,0 +1,33 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_public_access_blocked", + "CheckTitle": "Ensure OSS buckets block public access", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "critical", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets block public access to prevent unauthorized data exposure. Public buckets can be accessed by anyone on the internet, potentially exposing sensitive data.", + "Risk": "Public OSS buckets expose data to anyone on the internet, potentially leading to data breaches, unauthorized access to sensitive information, compliance violations, and reputational damage.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-public-access.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Configure OSS bucket ACL to block public access. Go to OSS Console > Buckets, select the bucket, and set ACL to 'Private'. Use bucket policies and RAM policies to grant access instead of public ACLs.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/bucket-acl" + } + }, + "Categories": [ + "encryption", + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.py new file mode 100644 index 0000000000..92ebaebf81 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_public_access_blocked + +Ensures that OSS buckets block public access to prevent unauthorized data exposure. +Public buckets can be accessed by anyone on the internet, potentially exposing sensitive data. + +Risk Level: CRITICAL +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_public_access_blocked(Check): + """Check if OSS buckets block public access""" + + def execute(self): + """Execute the oss_bucket_public_access_blocked check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if not bucket.public_access: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} blocks public access." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} allows public access. Configure bucket ACL to block public access to prevent unauthorized data exposure." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/__init__.py new file mode 100644 index 0000000000..4499b269ac --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Referer Whitelist Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.metadata.json new file mode 100644 index 0000000000..bcbe28f94c --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_referer_whitelist", + "CheckTitle": "Ensure OSS buckets have referer whitelist configured", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets have referer whitelist configured and do not allow empty referers. Referer whitelisting prevents hotlinking and unauthorized access from unknown sources.", + "Risk": "Without referer whitelist, buckets can be accessed from any source, potentially leading to bandwidth theft through hotlinking and unauthorized access to resources.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-referer.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Configure referer whitelist for OSS buckets and disable empty referers. Go to OSS Console > Buckets, select the bucket, and configure referer whitelist with trusted domains.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/hotlink-protection" + } + }, + "Categories": [ + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.py new file mode 100644 index 0000000000..c0f4e884c6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist.py @@ -0,0 +1,51 @@ +""" +Check: oss_bucket_referer_whitelist + +Ensures that OSS buckets have referer whitelist configured and do not allow empty referers. +Referer whitelisting prevents hotlinking and unauthorized access from unknown sources. + +Risk Level: LOW +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_referer_whitelist(Check): + """Check if OSS buckets have referer whitelist configured properly""" + + def execute(self): + """Execute the oss_bucket_referer_whitelist check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.referer_config: + allow_empty = bucket.referer_config.get("AllowEmpty", True) + referer_list = bucket.referer_config.get("RefererList", []) + + if allow_empty and (not referer_list or len(referer_list) == 0): + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} allows empty referers and has no referer whitelist. Configure referer whitelist and disable empty referers to prevent hotlinking." + elif allow_empty: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} allows empty referers. Disable empty referers to improve security." + elif not referer_list or len(referer_list) == 0: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} has no referer whitelist configured. Configure referer whitelist to control access." + else: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has proper referer whitelist configuration (AllowEmpty: False, {len(referer_list)} referer(s))." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} has no referer configuration. Configure referer whitelist to prevent hotlinking." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/__init__.py new file mode 100644 index 0000000000..82cdd760c6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Transfer Acceleration Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.metadata.json new file mode 100644 index 0000000000..c765067bed --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_transfer_acceleration", + "CheckTitle": "Check if OSS buckets have transfer acceleration enabled", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "informational", + "ResourceType": "Bucket", + "Description": "Checks if OSS buckets have transfer acceleration enabled for improved global data transfer performance. Transfer acceleration uses optimized network paths for faster uploads/downloads from distant locations.", + "Risk": "Without transfer acceleration, data transfers from distant geographic locations may be slower, impacting user experience and operational efficiency.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-transfer-acceleration.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable transfer acceleration for OSS buckets that serve global users. Go to OSS Console > Buckets, select the bucket, and enable transfer acceleration.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/transfer-acceleration" + } + }, + "Categories": [ + "trustworthy-ai" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This is an informational check. Transfer acceleration has additional costs." +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.py new file mode 100644 index 0000000000..3cd5e368f7 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_transfer_acceleration + +Checks if OSS buckets have transfer acceleration enabled for improved global data transfer performance. +Transfer acceleration uses optimized network paths for faster uploads/downloads from distant locations. + +Risk Level: INFORMATIONAL +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_transfer_acceleration(Check): + """Check if OSS buckets have transfer acceleration enabled""" + + def execute(self): + """Execute the oss_bucket_transfer_acceleration check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.transfer_acceleration: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has transfer acceleration enabled." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have transfer acceleration enabled. Consider enabling transfer acceleration for improved global data transfer performance." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/__init__.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/__init__.py new file mode 100644 index 0000000000..094fe42ef0 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/__init__.py @@ -0,0 +1 @@ +"""OSS Bucket Versioning Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.metadata.json b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.metadata.json new file mode 100644 index 0000000000..e470c07e6f --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "oss_bucket_versioning_enabled", + "CheckTitle": "Ensure OSS buckets have versioning enabled", + "CheckType": [], + "ServiceName": "oss", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Bucket", + "Description": "Ensures that OSS buckets have versioning enabled to protect against accidental deletions and overwrites. Versioning allows recovery of objects from accidental deletion or overwrite.", + "Risk": "Without versioning, accidental deletion or overwrite of objects cannot be recovered, potentially leading to permanent data loss.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/OSS/bucket-versioning.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable versioning for OSS buckets. Go to OSS Console > Buckets, select the bucket, and enable versioning.", + "Url": "https://www.alibabacloud.com/help/en/oss/user-guide/versioning" + } + }, + "Categories": [ + "forensics-ready" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.py b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.py new file mode 100644 index 0000000000..4fdea00536 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled.py @@ -0,0 +1,38 @@ +""" +Check: oss_bucket_versioning_enabled + +Ensures that OSS buckets have versioning enabled to protect against accidental deletions and overwrites. +Versioning allows recovery of objects from accidental deletion or overwrite. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.oss.oss_client import oss_client + + +class oss_bucket_versioning_enabled(Check): + """Check if OSS buckets have versioning enabled""" + + def execute(self): + """Execute the oss_bucket_versioning_enabled check""" + findings = [] + + for bucket_arn, bucket in oss_client.buckets.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=bucket) + report.account_uid = oss_client.account_id + report.region = bucket.region + report.resource_id = bucket.name + report.resource_arn = bucket.arn + + if bucket.versioning_enabled: + report.status = "PASS" + report.status_extended = f"OSS bucket {bucket.name} has versioning enabled." + else: + report.status = "FAIL" + report.status_extended = f"OSS bucket {bucket.name} does not have versioning enabled. Enable versioning to protect against accidental deletions and overwrites." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/oss/oss_client.py b/prowler/providers/alibabacloud/services/oss/oss_client.py new file mode 100644 index 0000000000..6d5e531cc6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud OSS Client Singleton""" + +from prowler.providers.alibabacloud.services.oss.oss_service import OSS +from prowler.providers.common.provider import Provider + +oss_client = OSS(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/oss/oss_service.py b/prowler/providers/alibabacloud/services/oss/oss_service.py new file mode 100644 index 0000000000..2701797af0 --- /dev/null +++ b/prowler/providers/alibabacloud/services/oss/oss_service.py @@ -0,0 +1,107 @@ +""" +Alibaba Cloud OSS Service + +This module provides the service class for Alibaba Cloud Object Storage Service (OSS). +""" + +from dataclasses import dataclass +from typing import Optional + +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class Bucket: + """OSS Bucket""" + name: str + arn: str + region: str + creation_date: str = "" + public_access: bool = True # Will trigger check + encryption_enabled: bool = False # Will trigger check + encryption_algorithm: str = "" + versioning_enabled: bool = False # Will trigger check + logging_enabled: bool = False # Will trigger check + access_logging_target: str = "" + lifecycle_rules: list = None + cors_rules: list = None + referer_config: dict = None + website_config: dict = None + transfer_acceleration: bool = False + tags: dict = None + + def __post_init__(self): + if self.lifecycle_rules is None: + self.lifecycle_rules = [] + if self.cors_rules is None: + self.cors_rules = [] + if self.referer_config is None: + self.referer_config = {} + if self.website_config is None: + self.website_config = {} + if self.tags is None: + self.tags = {} + + +class OSS(AlibabaCloudService): + """ + Alibaba Cloud OSS service class + + Handles collection of OSS resources including buckets, encryption settings, + access controls, and logging configuration. + """ + + def __init__(self, provider): + """Initialize OSS service""" + super().__init__("oss", provider) + + self.buckets = {} + + logger.info("Collecting OSS buckets...") + self._list_buckets() + + logger.info( + f"OSS service initialized - Buckets: {len(self.buckets)}" + ) + + def _list_buckets(self): + """List all OSS buckets""" + for region in self.regions: + try: + # TODO: Implement actual SDK call + # Placeholder: Create sample buckets for demonstration + bucket_name = f"prowler-demo-bucket-{region}" + arn = self.generate_resource_arn("bucket", bucket_name, region) + + bucket = Bucket( + name=bucket_name, + arn=arn, + region=region, + creation_date="2023-01-01", + public_access=True, # Should be False + encryption_enabled=False, # Should be True + encryption_algorithm="", # Should be AES256 or KMS + versioning_enabled=False, # Should be True + logging_enabled=False, # Should be True + access_logging_target="", + lifecycle_rules=[], + cors_rules=[ + { + "AllowedOrigin": ["*"], # Too permissive + "AllowedMethod": ["GET", "POST"], + } + ], + referer_config={ + "AllowEmpty": True, # Should be False + "RefererList": [] + }, + website_config={}, + transfer_acceleration=False, + tags={} + ) + + self.buckets[arn] = bucket + + except Exception as error: + self._handle_api_error(error, "ListBuckets", region) diff --git a/prowler/providers/alibabacloud/services/ram/__init__.py b/prowler/providers/alibabacloud/services/ram/__init__.py new file mode 100644 index 0000000000..777cf98e87 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud RAM (Resource Access Management) module""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/__init__.py new file mode 100644 index 0000000000..0795b08025 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/__init__.py @@ -0,0 +1 @@ +"""RAM Access Key Rotation Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.metadata.json new file mode 100644 index 0000000000..659504938d --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_access_key_rotation", + "CheckTitle": "Ensure RAM user access keys are rotated every 90 days or less", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "AccessKey", + "Description": "Ensures that RAM user access keys are rotated regularly (within 90 days). Regular access key rotation reduces the risk of unauthorized access from compromised keys.", + "Risk": "Access keys that are not rotated regularly increase the risk of unauthorized access if they are compromised. Older keys have had more time to potentially be exposed through logs, code repositories, or other means.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/access-key-rotation.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Rotate RAM user access keys that are older than 90 days. Create new access keys, update applications to use the new keys, and delete the old keys.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/create-an-accesskey-pair" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.py b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.py new file mode 100644 index 0000000000..f243f01894 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation.py @@ -0,0 +1,58 @@ +""" +Check: ram_access_key_rotation + +Ensures that RAM user access keys are rotated regularly (within 90 days). +Regular access key rotation reduces the risk of unauthorized access from compromised keys. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from datetime import datetime, timedelta +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_access_key_rotation(Check): + """Check if RAM user access keys are rotated within 90 days""" + + def execute(self): + """Execute the ram_access_key_rotation check""" + findings = [] + + for user_arn, user in ram_client.users.items(): + for access_key in user.access_keys: + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': access_key.access_key_id, + 'name': f"{user.name}-{access_key.access_key_id}", + 'arn': f"{user.arn}/access-key/{access_key.access_key_id}", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = access_key.access_key_id + report.resource_arn = f"{user.arn}/access-key/{access_key.access_key_id}" + + # Check if access key is older than 90 days + if access_key.create_date: + try: + create_date = datetime.fromisoformat(access_key.create_date.replace('Z', '+00:00')) + age_days = (datetime.now(create_date.tzinfo) - create_date).days + + if age_days <= 90: + report.status = "PASS" + report.status_extended = f"Access key {access_key.access_key_id} for user {user.name} is {age_days} days old (within the 90-day rotation period)." + else: + report.status = "FAIL" + report.status_extended = f"Access key {access_key.access_key_id} for user {user.name} is {age_days} days old. Rotate access keys at least every 90 days." + except Exception: + report.status = "FAIL" + report.status_extended = f"Unable to determine age of access key {access_key.access_key_id} for user {user.name}. Ensure access keys are rotated regularly." + else: + report.status = "FAIL" + report.status_extended = f"Access key {access_key.access_key_id} for user {user.name} has no creation date. Ensure access keys are rotated regularly." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_client.py b/prowler/providers/alibabacloud/services/ram/ram_client.py new file mode 100644 index 0000000000..39848822b9 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud RAM Client Singleton""" + +from prowler.providers.alibabacloud.services.ram.ram_service import RAM +from prowler.providers.common.provider import Provider + +ram_client = RAM(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/__init__.py new file mode 100644 index 0000000000..9624a3a1f3 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/__init__.py @@ -0,0 +1 @@ +"""RAM Inactive Users Disabled Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.metadata.json new file mode 100644 index 0000000000..7dcb589922 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.metadata.json @@ -0,0 +1,25 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_inactive_users_disabled", + "CheckTitle": "Ensure inactive RAM users are disabled", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "User", + "Description": "Ensures that inactive RAM users (90+ days without login) are disabled or removed.", + "Risk": "Inactive accounts pose security risks as they may have outdated permissions or be compromised without detection.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/inactive-users.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": { + "Text": "Disable or remove RAM users that have been inactive for 90+ days.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/manage-ram-users" + } + }, + "Categories": ["identity-and-access"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.py b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.py new file mode 100644 index 0000000000..1d7a2b41d8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled.py @@ -0,0 +1,54 @@ +""" +Check: ram_inactive_users_disabled + +Ensures that inactive RAM users are disabled or removed. +Inactive accounts pose a security risk as they may be forgotten and have outdated permissions. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from datetime import datetime, timedelta +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_inactive_users_disabled(Check): + """Check if inactive RAM users (90+ days without login) are disabled""" + + def execute(self): + """Execute the ram_inactive_users_disabled check""" + findings = [] + + for user_arn, user in ram_client.users.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=user) + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = user.id + report.resource_arn = user.arn + + # Check if user has console login enabled + if user.console_login_enabled and user.last_login_date: + try: + last_login = datetime.fromisoformat(user.last_login_date.replace('Z', '+00:00')) + days_inactive = (datetime.now(last_login.tzinfo) - last_login).days + + if days_inactive <= 90: + report.status = "PASS" + report.status_extended = f"RAM user {user.name} was last active {days_inactive} days ago (within 90-day threshold)." + else: + report.status = "FAIL" + report.status_extended = f"RAM user {user.name} has been inactive for {days_inactive} days. Disable or remove inactive users." + except Exception: + report.status = "FAIL" + report.status_extended = f"Unable to determine last login date for RAM user {user.name}. Review user activity." + elif user.console_login_enabled: + report.status = "FAIL" + report.status_extended = f"RAM user {user.name} has console access but no recorded login. Review if user is needed." + else: + report.status = "PASS" + report.status_extended = f"RAM user {user.name} does not have console login enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/__init__.py new file mode 100644 index 0000000000..8f5ed20678 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/__init__.py @@ -0,0 +1 @@ +"""RAM No Admin Privileges Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.metadata.json new file mode 100644 index 0000000000..600d86281f --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.metadata.json @@ -0,0 +1,25 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_no_admin_privileges", + "CheckTitle": "Ensure RAM users do not have unnecessary administrative privileges", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "User", + "Description": "Ensures that RAM users do not have administrative privileges unless absolutely necessary.", + "Risk": "Users with administrative privileges have unrestricted access, increasing the risk of accidental or malicious damage.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/admin-privileges.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": { + "Text": "Remove administrative policies from RAM users and grant only necessary permissions.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/grant-permissions-to-a-ram-user" + } + }, + "Categories": ["identity-and-access"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.py b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.py new file mode 100644 index 0000000000..1cb9ea70b6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges.py @@ -0,0 +1,49 @@ +""" +Check: ram_no_admin_privileges + +Ensures that RAM users do not have administrative privileges. +Following principle of least privilege, admin access should be granted only when necessary. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_no_admin_privileges(Check): + """Check if RAM users have unnecessary administrative privileges""" + + def execute(self): + """Execute the ram_no_admin_privileges check""" + findings = [] + + for user_arn, user in ram_client.users.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=user) + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = user.id + report.resource_arn = user.arn + + # Check if user has AdministratorAccess policy + has_admin = False + admin_policies = [] + + if user.attached_policies: + for policy in user.attached_policies: + policy_name = policy.get("PolicyName", "") + if "Administrator" in policy_name or "FullAccess" in policy_name: + has_admin = True + admin_policies.append(policy_name) + + if not has_admin: + report.status = "PASS" + report.status_extended = f"RAM user {user.name} does not have administrative privileges." + else: + report.status = "FAIL" + report.status_extended = f"RAM user {user.name} has administrative privileges via: {', '.join(admin_policies)}. Follow principle of least privilege." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_expiration/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/__init__.py new file mode 100644 index 0000000000..711a5798d6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/__init__.py @@ -0,0 +1 @@ +"""RAM Password Expiration Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.metadata.json new file mode 100644 index 0000000000..7db313a973 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_expiration", + "CheckTitle": "Ensure RAM password policy requires password expiration within 90 days", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires password expiration within 90 days or less. Regular password rotation reduces the window of opportunity for compromised credentials to be exploited.", + "Risk": "Passwords that never expire or expire after a long period increase the risk of unauthorized access from compromised credentials. Attackers have more time to use stolen credentials.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-expiration.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require password expiration within 90 days or less. Go to RAM Console > Settings > Security Settings and set the maximum password age to 90 days or less.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.py b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.py new file mode 100644 index 0000000000..523a51e1c8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration.py @@ -0,0 +1,51 @@ +""" +Check: ram_password_expiration + +Ensures that the RAM password policy requires password expiration within 90 days or less. +Regular password rotation reduces the window of opportunity for compromised credentials to be exploited. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_expiration(Check): + """Check if the RAM password policy requires password expiration within 90 days""" + + def execute(self): + """Execute the ram_password_expiration check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy: + max_age = ram_client.password_policy.max_password_age + + if 0 < max_age <= 90: + report.status = "PASS" + report.status_extended = f"RAM password policy requires passwords to expire within {max_age} days (meets the 90-day requirement)." + elif max_age == 0: + report.status = "FAIL" + report.status_extended = "RAM password policy does not require password expiration. Set maximum password age to 90 days or less." + else: + report.status = "FAIL" + report.status_extended = f"RAM password policy allows passwords to remain valid for {max_age} days. Reduce the maximum password age to 90 days or less." + else: + report.status = "FAIL" + report.status_extended = "No RAM password policy is configured. Configure a password policy with a maximum password age of 90 days or less." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/__init__.py new file mode 100644 index 0000000000..c665d3bce7 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/__init__.py @@ -0,0 +1 @@ +"""RAM Password Minimum Length Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.metadata.json new file mode 100644 index 0000000000..3f54e3ed12 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_minimum_length", + "CheckTitle": "Ensure RAM password policy requires minimum length of 14 or greater", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires a minimum length of at least 14 characters. Longer passwords are generally more secure as they are harder to crack through brute-force attacks.", + "Risk": "Short passwords are vulnerable to brute-force attacks and dictionary attacks. Attackers can more easily guess or crack shorter passwords, potentially leading to unauthorized account access.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-minimum-length.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require a minimum length of at least 14 characters. Go to RAM Console > Settings > Security Settings and set the minimum password length to 14 or greater.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.py b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.py new file mode 100644 index 0000000000..444e02dad8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length.py @@ -0,0 +1,49 @@ +""" +Check: ram_password_minimum_length + +Ensures that the RAM password policy requires a minimum length of at least 14 characters. +Longer passwords are generally more secure as they are harder to crack through brute-force attacks. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_minimum_length(Check): + """Check if the RAM password policy requires a minimum length of at least 14 characters""" + + def execute(self): + """Execute the ram_password_minimum_length check""" + findings = [] + + # Create a report for the password policy + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy: + minimum_length = ram_client.password_policy.minimum_length + + if minimum_length >= 14: + report.status = "PASS" + report.status_extended = f"RAM password policy requires a minimum length of {minimum_length} characters (meets the 14+ character requirement)." + else: + report.status = "FAIL" + report.status_extended = f"RAM password policy requires a minimum length of only {minimum_length} characters. Increase the minimum password length to at least 14 characters." + else: + report.status = "FAIL" + report.status_extended = "No RAM password policy is configured. Configure a password policy with a minimum length of at least 14 characters." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/__init__.py new file mode 100644 index 0000000000..3692a2b6b6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/__init__.py @@ -0,0 +1 @@ +"""RAM Password Require Lowercase Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.metadata.json new file mode 100644 index 0000000000..b116220d3f --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_require_lowercase", + "CheckTitle": "Ensure RAM password policy requires at least one lowercase letter", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires at least one lowercase letter. This increases password complexity and makes them more resistant to attacks.", + "Risk": "Passwords without lowercase letter requirements are less complex and easier to crack through brute-force or dictionary attacks.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-lowercase.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require at least one lowercase letter. Go to RAM Console > Settings > Security Settings and enable the lowercase letter requirement.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.py new file mode 100644 index 0000000000..e0abe92e92 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase.py @@ -0,0 +1,42 @@ +""" +Check: ram_password_require_lowercase + +Ensures that the RAM password policy requires at least one lowercase letter. +This increases password complexity and makes them more resistant to attacks. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_require_lowercase(Check): + """Check if the RAM password policy requires at least one lowercase letter""" + + def execute(self): + """Execute the ram_password_require_lowercase check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy and ram_client.password_policy.require_lowercase: + report.status = "PASS" + report.status_extended = "RAM password policy requires at least one lowercase letter." + else: + report.status = "FAIL" + report.status_extended = "RAM password policy does not require lowercase letters. Enable the lowercase letter requirement to increase password complexity." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/__init__.py new file mode 100644 index 0000000000..ca606480d3 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/__init__.py @@ -0,0 +1 @@ +"""RAM Password Require Numbers Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.metadata.json new file mode 100644 index 0000000000..1c5f34add7 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_require_numbers", + "CheckTitle": "Ensure RAM password policy requires at least one number", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires at least one number. This increases password complexity and makes them more resistant to attacks.", + "Risk": "Passwords without number requirements are less complex and easier to crack through brute-force or dictionary attacks.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-numbers.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require at least one number. Go to RAM Console > Settings > Security Settings and enable the number requirement.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.py new file mode 100644 index 0000000000..08c7d0d5fd --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers.py @@ -0,0 +1,42 @@ +""" +Check: ram_password_require_numbers + +Ensures that the RAM password policy requires at least one number. +This increases password complexity and makes them more resistant to attacks. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_require_numbers(Check): + """Check if the RAM password policy requires at least one number""" + + def execute(self): + """Execute the ram_password_require_numbers check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy and ram_client.password_policy.require_numbers: + report.status = "PASS" + report.status_extended = "RAM password policy requires at least one number." + else: + report.status = "FAIL" + report.status_extended = "RAM password policy does not require numbers. Enable the number requirement to increase password complexity." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/__init__.py new file mode 100644 index 0000000000..646f8f6225 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/__init__.py @@ -0,0 +1 @@ +"""RAM Password Require Symbols Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.metadata.json new file mode 100644 index 0000000000..0efd4d10c0 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_require_symbols", + "CheckTitle": "Ensure RAM password policy requires at least one symbol", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires at least one symbol (special character). This increases password complexity and makes them more resistant to attacks.", + "Risk": "Passwords without symbol requirements are less complex and easier to crack through brute-force or dictionary attacks.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-symbols.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require at least one symbol. Go to RAM Console > Settings > Security Settings and enable the symbol requirement.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.py new file mode 100644 index 0000000000..ac690371db --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols.py @@ -0,0 +1,42 @@ +""" +Check: ram_password_require_symbols + +Ensures that the RAM password policy requires at least one symbol (special character). +This increases password complexity and makes them more resistant to attacks. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_require_symbols(Check): + """Check if the RAM password policy requires at least one symbol""" + + def execute(self): + """Execute the ram_password_require_symbols check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy and ram_client.password_policy.require_symbols: + report.status = "PASS" + report.status_extended = "RAM password policy requires at least one symbol (special character)." + else: + report.status = "FAIL" + report.status_extended = "RAM password policy does not require symbols. Enable the symbol requirement to increase password complexity." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/__init__.py new file mode 100644 index 0000000000..75a1cda23c --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/__init__.py @@ -0,0 +1 @@ +"""RAM Password Require Uppercase Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.metadata.json new file mode 100644 index 0000000000..e414c3211c --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_require_uppercase", + "CheckTitle": "Ensure RAM password policy requires at least one uppercase letter", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy requires at least one uppercase letter. This increases password complexity and makes them more resistant to attacks.", + "Risk": "Passwords without uppercase letter requirements are less complex and easier to crack through brute-force or dictionary attacks.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-uppercase.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to require at least one uppercase letter. Go to RAM Console > Settings > Security Settings and enable the uppercase letter requirement.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.py b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.py new file mode 100644 index 0000000000..111eb9247e --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase.py @@ -0,0 +1,42 @@ +""" +Check: ram_password_require_uppercase + +Ensures that the RAM password policy requires at least one uppercase letter. +This increases password complexity and makes them more resistant to attacks. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_require_uppercase(Check): + """Check if the RAM password policy requires at least one uppercase letter""" + + def execute(self): + """Execute the ram_password_require_uppercase check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy and ram_client.password_policy.require_uppercase: + report.status = "PASS" + report.status_extended = "RAM password policy requires at least one uppercase letter." + else: + report.status = "FAIL" + report.status_extended = "RAM password policy does not require uppercase letters. Enable the uppercase letter requirement to increase password complexity." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/__init__.py new file mode 100644 index 0000000000..2536f4fb09 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/__init__.py @@ -0,0 +1 @@ +"""RAM Password Retry Limits Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.metadata.json new file mode 100644 index 0000000000..e7c6b0531c --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.metadata.json @@ -0,0 +1,25 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_retry_limits", + "CheckTitle": "Ensure RAM password policy has login retry limits", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy has login retry limits configured to prevent brute-force attacks.", + "Risk": "Without login retry limits, accounts are vulnerable to brute-force password attacks.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-retry-limits.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": { + "Text": "Configure login retry limits in the RAM password policy to 5 or fewer attempts.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": ["identity-and-access"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.py b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.py new file mode 100644 index 0000000000..81c5182266 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits.py @@ -0,0 +1,48 @@ +""" +Check: ram_password_retry_limits + +Ensures that the RAM password policy has login retry limits configured. +This prevents brute-force attacks by locking accounts after failed login attempts. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_retry_limits(Check): + """Check if the RAM password policy has appropriate login retry limits""" + + def execute(self): + """Execute the ram_password_retry_limits check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy: + max_attempts = ram_client.password_policy.max_login_attempts + + if 1 <= max_attempts <= 5: + report.status = "PASS" + report.status_extended = f"RAM password policy limits login attempts to {max_attempts} (meets the 1-5 requirement)." + else: + report.status = "FAIL" + report.status_extended = f"RAM password policy allows {max_attempts} login attempts. Set maximum login attempts between 1 and 5 to prevent brute-force attacks." + else: + report.status = "FAIL" + report.status_extended = "No RAM password policy is configured. Configure a password policy with login retry limits." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/__init__.py new file mode 100644 index 0000000000..bf32664607 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/__init__.py @@ -0,0 +1 @@ +"""RAM Password Reuse Prevention Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.metadata.json new file mode 100644 index 0000000000..32543a6b0a --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_password_reuse_prevention", + "CheckTitle": "Ensure RAM password policy prevents password reuse", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "PasswordPolicy", + "Description": "Ensures that the RAM password policy prevents password reuse. Preventing password reuse helps ensure that old passwords, which may have been compromised, cannot be reused.", + "Risk": "Allowing password reuse may allow attackers to use previously compromised credentials to gain access to accounts.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/password-policy-reuse.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the RAM password policy to prevent password reuse. Go to RAM Console > Settings > Security Settings and enable password reuse prevention (recommend preventing reuse of at least the last 5 passwords).", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/set-a-password-policy-for-ram-users" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.py b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.py new file mode 100644 index 0000000000..9a31c26eea --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention.py @@ -0,0 +1,48 @@ +""" +Check: ram_password_reuse_prevention + +Ensures that the RAM password policy prevents password reuse. +Preventing password reuse helps ensure that old passwords, which may have been compromised, cannot be reused. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_password_reuse_prevention(Check): + """Check if the RAM password policy prevents password reuse""" + + def execute(self): + """Execute the ram_password_reuse_prevention check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'password-policy', + 'name': 'RAM Password Policy', + 'arn': f"acs:ram::{ram_client.account_id}:password-policy", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "password-policy" + report.resource_arn = f"acs:ram::{ram_client.account_id}:password-policy" + + if ram_client.password_policy: + reuse_prevention = ram_client.password_policy.password_reuse_prevention + + if reuse_prevention > 0: + report.status = "PASS" + report.status_extended = f"RAM password policy prevents reuse of the last {reuse_prevention} password(s)." + else: + report.status = "FAIL" + report.status_extended = "RAM password policy does not prevent password reuse. Enable password reuse prevention to improve security." + else: + report.status = "FAIL" + report.status_extended = "No RAM password policy is configured. Configure a password policy with password reuse prevention enabled." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/__init__.py new file mode 100644 index 0000000000..ee124777ac --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/__init__.py @@ -0,0 +1 @@ +"""RAM Root Access Keys Absent Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.metadata.json new file mode 100644 index 0000000000..53e64ea427 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_root_access_keys_absent", + "CheckTitle": "Ensure root account does not have active access keys", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "critical", + "ResourceType": "Account", + "Description": "Ensures that the root account does not have any active access keys. The root account has unrestricted access to all resources. Using access keys for the root account increases the risk of credential exposure.", + "Risk": "Root account access keys provide unrestricted access to all resources. If these keys are compromised, attackers gain complete control over the account, potentially leading to data breaches, resource deletion, or unauthorized access to sensitive information.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/root-access-keys.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Delete all access keys associated with the root account. Use RAM users with appropriate permissions instead of the root account for day-to-day operations.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/create-an-accesskey-pair" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.py b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.py new file mode 100644 index 0000000000..51e5388b23 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent.py @@ -0,0 +1,44 @@ +""" +Check: ram_root_access_keys_absent + +Ensures that the root account does not have any active access keys. +The root account has unrestricted access to all resources. Using access keys for the root account +increases the risk of credential exposure. + +Risk Level: CRITICAL +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_root_access_keys_absent(Check): + """Check if the root account has any active access keys""" + + def execute(self): + """Execute the ram_root_access_keys_absent check""" + findings = [] + + # Create a report for the root account + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'root-account', + 'name': 'Root Account', + 'arn': f"acs:ram::{ram_client.account_id}:root", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "root-account" + report.resource_arn = f"acs:ram::{ram_client.account_id}:root" + + if not ram_client.root_has_access_keys: + report.status = "PASS" + report.status_extended = "Root account does not have any active access keys." + else: + report.status = "FAIL" + report.status_extended = "Root account has active access keys. Remove all access keys from the root account and use RAM users instead." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/__init__.py new file mode 100644 index 0000000000..94eb934962 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/__init__.py @@ -0,0 +1 @@ +"""RAM Root MFA Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.metadata.json new file mode 100644 index 0000000000..0de871468e --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_root_mfa_enabled", + "CheckTitle": "Ensure MFA is enabled for the root account", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Account", + "Description": "Ensures that multi-factor authentication (MFA) is enabled for the root account. The root account has unrestricted access to all resources in the Alibaba Cloud account. MFA adds an extra layer of protection on top of the username and password.", + "Risk": "Without MFA enabled, the root account is vulnerable to unauthorized access if credentials are compromised. This could lead to complete account takeover and access to all resources.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/root-mfa.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable MFA for the root account through the Alibaba Cloud console. Go to RAM Console > Settings > Security Settings and enable MFA for the root account.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/enable-an-mfa-device-for-an-alibaba-cloud-account" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.py b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.py new file mode 100644 index 0000000000..8e1d99af58 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled.py @@ -0,0 +1,44 @@ +""" +Check: ram_root_mfa_enabled + +Ensures that multi-factor authentication (MFA) is enabled for the root account. +The root account has unrestricted access to all resources in the Alibaba Cloud account. +MFA adds an extra layer of protection on top of the username and password. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_root_mfa_enabled(Check): + """Check if MFA is enabled for the root account""" + + def execute(self): + """Execute the ram_root_mfa_enabled check""" + findings = [] + + # Create a report for the root account + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'root-account', + 'name': 'Root Account', + 'arn': f"acs:ram::{ram_client.account_id}:root", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "root-account" + report.resource_arn = f"acs:ram::{ram_client.account_id}:root" + + if ram_client.root_mfa_enabled: + report.status = "PASS" + report.status_extended = "Root account has MFA enabled." + else: + report.status = "FAIL" + report.status_extended = "Root account does not have MFA enabled. Enable MFA for the root account to add an extra layer of security." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/__init__.py new file mode 100644 index 0000000000..8cee612eb4 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/__init__.py @@ -0,0 +1 @@ +"""RAM Root Usage Minimized Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.metadata.json new file mode 100644 index 0000000000..de055deccd --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.metadata.json @@ -0,0 +1,25 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_root_usage_minimized", + "CheckTitle": "Ensure root account usage is minimized", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Account", + "Description": "Ensures that root account usage is minimized. Root account should only be used for account management.", + "Risk": "Regular use of root account increases risk of credential compromise and accidental damage.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/root-usage.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": { + "Text": "Stop using root account for day-to-day operations. Use RAM users with appropriate permissions instead.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/overview-of-ram" + } + }, + "Categories": ["identity-and-access"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.py b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.py new file mode 100644 index 0000000000..cd1ce68c72 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized.py @@ -0,0 +1,54 @@ +""" +Check: ram_root_usage_minimized + +Ensures that root account usage is minimized. +The root account should only be used for account management, not day-to-day operations. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from datetime import datetime, timedelta +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_root_usage_minimized(Check): + """Check if root account usage is minimized""" + + def execute(self): + """Execute the ram_root_usage_minimized check""" + findings = [] + + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'root-account', + 'name': 'Root Account', + 'arn': f"acs:ram::{ram_client.account_id}:root", + 'region': 'global' + })()) + + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = "root-account" + report.resource_arn = f"acs:ram::{ram_client.account_id}:root" + + if ram_client.root_last_activity: + try: + last_activity = datetime.fromisoformat(ram_client.root_last_activity.replace('Z', '+00:00')) + days_since_activity = (datetime.now(last_activity.tzinfo) - last_activity).days + + if days_since_activity >= 90: + report.status = "PASS" + report.status_extended = f"Root account has not been used in the last {days_since_activity} days (inactive for 90+ days)." + else: + report.status = "FAIL" + report.status_extended = f"Root account was used {days_since_activity} days ago. Minimize root account usage and use RAM users instead." + except Exception: + report.status = "FAIL" + report.status_extended = "Unable to determine root account last activity. Review root account usage." + else: + report.status = "PASS" + report.status_extended = "No recent root account activity detected." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_service.py b/prowler/providers/alibabacloud/services/ram/ram_service.py new file mode 100644 index 0000000000..97823c15de --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_service.py @@ -0,0 +1,153 @@ +""" +Alibaba Cloud RAM Service + +This module provides the service class for Alibaba Cloud Resource Access Management (RAM). +""" + +from dataclasses import dataclass +from typing import Optional + +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class User: + """RAM User""" + id: str + name: str + arn: str + create_date: str = "" + console_login_enabled: bool = False + mfa_enabled: bool = False + access_keys: list = None + attached_policies: list = None + groups: list = None + last_login_date: str = "" + + def __post_init__(self): + if self.access_keys is None: + self.access_keys = [] + if self.attached_policies is None: + self.attached_policies = [] + if self.groups is None: + self.groups = [] + + +@dataclass +class PasswordPolicy: + """RAM Password Policy""" + minimum_length: int = 8 + require_lowercase: bool = False + require_uppercase: bool = False + require_numbers: bool = False + require_symbols: bool = False + max_login_attempts: int = 5 + max_password_age: int = 0 # 0 = no expiration + password_reuse_prevention: int = 0 # 0 = no prevention + hard_expiry: bool = False + + +@dataclass +class AccessKey: + """RAM Access Key""" + access_key_id: str + user_name: str + status: str = "Active" + create_date: str = "" + last_used_date: str = "" + + +class RAM(AlibabaCloudService): + """ + Alibaba Cloud RAM service class + + Handles collection of RAM resources including users, password policies, + access keys, and root account configuration. + """ + + def __init__(self, provider): + """Initialize RAM service""" + super().__init__("ram", provider) + + self.users = {} + self.password_policy = None + self.root_mfa_enabled = False + self.root_has_access_keys = False + self.root_last_activity = None + + logger.info("Collecting RAM users...") + self._list_users() + + logger.info("Collecting RAM password policy...") + self._get_password_policy() + + logger.info("Checking root account configuration...") + self._check_root_account() + + logger.info( + f"RAM service initialized - Users: {len(self.users)}" + ) + + def _list_users(self): + """List all RAM users""" + for region in self.regions: + try: + # TODO: Implement actual SDK call + # Placeholder: Create sample users for demonstration + user_id = f"ram-user-sample-{region}" + arn = self.generate_resource_arn("user", user_id, "") + + user = User( + id=user_id, + name=f"sample-user-{region}", + arn=arn, + console_login_enabled=True, + mfa_enabled=False, # Will trigger MFA check + access_keys=[ + AccessKey( + access_key_id="LTAI_sample", + user_name=f"sample-user-{region}", + create_date="2023-01-01" + ) + ], + attached_policies=[ + {"PolicyName": "AdministratorAccess", "PolicyType": "System"} + ] + ) + + self.users[arn] = user + + except Exception as error: + self._handle_api_error(error, "ListUsers", region) + + def _get_password_policy(self): + """Get RAM password policy""" + try: + # TODO: Implement actual SDK call + # Placeholder: Create sample policy + self.password_policy = PasswordPolicy( + minimum_length=8, # Should be 14 + require_lowercase=False, # Should be True + require_uppercase=False, # Should be True + require_numbers=False, # Should be True + require_symbols=False, # Should be True + max_login_attempts=5, + max_password_age=0, # Should be 90 + password_reuse_prevention=0 # Should be >0 + ) + + except Exception as error: + self._handle_api_error(error, "GetPasswordPolicy", "global") + + def _check_root_account(self): + """Check root account configuration""" + try: + # TODO: Implement actual SDK calls + # Placeholder values + self.root_mfa_enabled = False # Should be True + self.root_has_access_keys = True # Should be False + self.root_last_activity = "2024-01-01" + + except Exception as error: + self._handle_api_error(error, "CheckRootAccount", "global") diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/__init__.py new file mode 100644 index 0000000000..40ffc5bd9d --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/__init__.py @@ -0,0 +1 @@ +"""RAM User MFA Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.metadata.json new file mode 100644 index 0000000000..d58ec08c7e --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_user_mfa_enabled", + "CheckTitle": "Ensure MFA is enabled for all RAM users with console access", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "User", + "Description": "Ensures that multi-factor authentication (MFA) is enabled for all RAM users with console access. MFA adds an extra layer of security by requiring users to provide a unique authentication code from an approved authentication device in addition to their username and password.", + "Risk": "Without MFA enabled, user accounts are vulnerable to unauthorized access if credentials are compromised. This could lead to data breaches, unauthorized resource access, or malicious activities.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/user-mfa.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable MFA for all RAM users with console access. Go to RAM Console > Users, select each user, and enable MFA device binding.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/enable-an-mfa-device-for-a-ram-user" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.py b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.py new file mode 100644 index 0000000000..766e16d1cf --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled.py @@ -0,0 +1,41 @@ +""" +Check: ram_user_mfa_enabled + +Ensures that multi-factor authentication (MFA) is enabled for all RAM users with console access. +MFA adds an extra layer of security by requiring users to provide a unique authentication code +from an approved authentication device in addition to their username and password. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_user_mfa_enabled(Check): + """Check if MFA is enabled for all RAM users with console access""" + + def execute(self): + """Execute the ram_user_mfa_enabled check""" + findings = [] + + for user_arn, user in ram_client.users.items(): + # Only check users with console login enabled + if user.console_login_enabled: + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=user) + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = user.id + report.resource_arn = user.arn + + if user.mfa_enabled: + report.status = "PASS" + report.status_extended = f"RAM user {user.name} has MFA enabled." + else: + report.status = "FAIL" + report.status_extended = f"RAM user {user.name} has console access but does not have MFA enabled. Enable MFA to add an extra layer of security." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/__init__.py b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/__init__.py new file mode 100644 index 0000000000..7e5f0d884b --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/__init__.py @@ -0,0 +1 @@ +"""RAM User Policy Via Groups Check""" diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.metadata.json b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.metadata.json new file mode 100644 index 0000000000..d7374f0315 --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "ram_user_policy_via_groups", + "CheckTitle": "Ensure RAM users receive permissions through groups", + "CheckType": [], + "ServiceName": "ram", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "User", + "Description": "Ensures that RAM users receive permissions only through group membership, not through directly attached policies. Using groups makes permission management easier and more consistent across users with similar roles.", + "Risk": "Directly attaching policies to individual users makes permission management difficult and increases the risk of misconfiguration or inconsistent permissions across users with similar roles.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/RAM/user-policy-via-groups.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Remove directly attached policies from RAM users and add users to appropriate groups instead. Create groups with the required policies and add users to these groups.", + "Url": "https://www.alibabacloud.com/help/en/ram/user-guide/create-a-ram-user-group" + } + }, + "Categories": [ + "identity-and-access" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.py b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.py new file mode 100644 index 0000000000..e74e1f1eab --- /dev/null +++ b/prowler/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups.py @@ -0,0 +1,40 @@ +""" +Check: ram_user_policy_via_groups + +Ensures that RAM users receive permissions only through group membership, not through directly attached policies. +Using groups makes permission management easier and more consistent across users with similar roles. + +Risk Level: LOW +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.ram.ram_client import ram_client + + +class ram_user_policy_via_groups(Check): + """Check if RAM users receive permissions through groups rather than direct policy attachment""" + + def execute(self): + """Execute the ram_user_policy_via_groups check""" + findings = [] + + for user_arn, user in ram_client.users.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=user) + report.account_uid = ram_client.account_id + report.region = "global" + report.resource_id = user.id + report.resource_arn = user.arn + + # Check if user has directly attached policies + if user.attached_policies and len(user.attached_policies) > 0: + policy_names = [p.get("PolicyName", "Unknown") for p in user.attached_policies] + report.status = "FAIL" + report.status_extended = f"RAM user {user.name} has {len(user.attached_policies)} directly attached policy/policies: {', '.join(policy_names)}. Remove direct policy attachments and use group membership instead." + else: + report.status = "PASS" + report.status_extended = f"RAM user {user.name} does not have any directly attached policies (uses group-based permissions)." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/__init__.py b/prowler/providers/alibabacloud/services/rds/__init__.py new file mode 100644 index 0000000000..4383932def --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud RDS (Relational Database Service) module""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_client.py b/prowler/providers/alibabacloud/services/rds/rds_client.py new file mode 100644 index 0000000000..a745233c3a --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud RDS Client Singleton""" + +from prowler.providers.alibabacloud.services.rds.rds_service import RDS +from prowler.providers.common.provider import Provider + +rds_client = RDS(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py new file mode 100644 index 0000000000..dc4ad871e1 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py @@ -0,0 +1 @@ +"""RDS Audit Logging Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.metadata.json new file mode 100644 index 0000000000..db8ae4ad37 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_audit_log", + "CheckTitle": "Check RDS Audit Logging", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS Audit Logging.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.py b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.py new file mode 100644 index 0000000000..7c3702c554 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_audit_log + +Ensures that RDS instances have SQL audit logging enabled. +Audit logs record database operations for security monitoring and compliance. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_audit_log(Check): + """Check if RDS instances have audit logging enabled""" + + def execute(self): + """Execute the rds_instance_audit_log check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.audit_log_enabled: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has SQL audit logging enabled." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have SQL audit logging enabled. Enable audit logging for security monitoring and compliance." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py new file mode 100644 index 0000000000..8e5f6c9993 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py @@ -0,0 +1 @@ +"""RDS Auto Minor Version Upgrade Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.metadata.json new file mode 100644 index 0000000000..d4f429b2b2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_auto_minor_version_upgrade", + "CheckTitle": "Check RDS Auto Minor Version Upgrade", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "DBInstance", + "Description": "Checks RDS Auto Minor Version Upgrade.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.py b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.py new file mode 100644 index 0000000000..926025a50f --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_auto_minor_version_upgrade + +Ensures that RDS instances have automatic minor version upgrades enabled. +Auto minor version upgrades apply security patches and bug fixes automatically. + +Risk Level: LOW +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_auto_minor_version_upgrade(Check): + """Check if RDS instances have automatic minor version upgrades enabled""" + + def execute(self): + """Execute the rds_instance_auto_minor_version_upgrade check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.auto_minor_version_upgrade: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has automatic minor version upgrades enabled." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have automatic minor version upgrades enabled. Enable auto upgrades for security patches." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py new file mode 100644 index 0000000000..22e7cee1dc --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py @@ -0,0 +1 @@ +"""RDS Backup Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.metadata.json new file mode 100644 index 0000000000..47e08cfbc3 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_backup_enabled", + "CheckTitle": "Check RDS Backup", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS Backup.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.py b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.py new file mode 100644 index 0000000000..0809379314 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_backup_enabled + +Ensures that RDS instances have automated backups enabled. +Automated backups enable point-in-time recovery and data protection. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_backup_enabled(Check): + """Check if RDS instances have automated backups enabled""" + + def execute(self): + """Execute the rds_instance_backup_enabled check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.backup_enabled: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has automated backups enabled." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have automated backups enabled. Enable automated backups for data protection." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py new file mode 100644 index 0000000000..936ed1f35f --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py @@ -0,0 +1 @@ +"""RDS Deletion Protection Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.metadata.json new file mode 100644 index 0000000000..1eef4bc10d --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_deletion_protection", + "CheckTitle": "Check RDS Deletion Protection", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS Deletion Protection.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.py b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.py new file mode 100644 index 0000000000..c91901e10c --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_deletion_protection + +Ensures that RDS instances have deletion protection enabled. +Deletion protection prevents accidental deletion of database instances. + +Risk Level: MEDIUM +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_deletion_protection(Check): + """Check if RDS instances have deletion protection enabled""" + + def execute(self): + """Execute the rds_instance_deletion_protection check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.deletion_protection: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has deletion protection enabled." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have deletion protection enabled. Enable deletion protection to prevent accidental deletion." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py new file mode 100644 index 0000000000..58c05fcdce --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py @@ -0,0 +1 @@ +"""RDS Encryption Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.metadata.json new file mode 100644 index 0000000000..311282b847 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_encryption", + "CheckTitle": "Check RDS Encryption", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "DBInstance", + "Description": "Checks RDS Encryption.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.py b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.py new file mode 100644 index 0000000000..5aafc2ee74 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_encryption + +Ensures that RDS instances have Transparent Data Encryption (TDE) enabled. +Encryption protects sensitive database data at rest. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_encryption(Check): + """Check if RDS instances have encryption enabled""" + + def execute(self): + """Execute the rds_instance_encryption check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.encryption_enabled: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has Transparent Data Encryption (TDE) enabled." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have Transparent Data Encryption (TDE) enabled. Enable TDE to protect data at rest." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py new file mode 100644 index 0000000000..7d4dc7e425 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py @@ -0,0 +1 @@ +"""RDS VPC Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.metadata.json new file mode 100644 index 0000000000..7c2ebe139e --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_in_vpc", + "CheckTitle": "Check RDS VPC", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS VPC.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.py b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.py new file mode 100644 index 0000000000..2d894f3666 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_in_vpc + +Ensures that RDS instances are deployed within a VPC. +Running databases in a VPC provides network isolation and enhanced security controls. + +Risk Level: HIGH +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_in_vpc(Check): + """Check if RDS instances are deployed in a VPC""" + + def execute(self): + """Execute the rds_instance_in_vpc check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.vpc_id: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} is deployed in VPC {db_instance.vpc_id}." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} is not deployed in a VPC. Deploy the instance in a VPC for network isolation and enhanced security." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py new file mode 100644 index 0000000000..0e37b20018 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py @@ -0,0 +1 @@ +"""RDS Multi-AZ Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.metadata.json new file mode 100644 index 0000000000..012dae0921 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_multi_az", + "CheckTitle": "Check RDS Multi-AZ", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS Multi-AZ.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.py b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.py new file mode 100644 index 0000000000..4f4849ede2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_multi_az + +Ensures that RDS instances are deployed across multiple availability zones for high availability. +Multi-AZ deployments provide enhanced database availability and durability. + +Risk Level: MEDIUM +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_multi_az(Check): + """Check if RDS instances are deployed in multiple availability zones""" + + def execute(self): + """Execute the rds_instance_multi_az check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.multi_az: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} is deployed across multiple availability zones." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} is not deployed across multiple availability zones. Enable Multi-AZ for high availability." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py new file mode 100644 index 0000000000..7601b5bf06 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py @@ -0,0 +1 @@ +"""RDS Public Access Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.metadata.json new file mode 100644 index 0000000000..f274672061 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_public_access", + "CheckTitle": "Check RDS Public Access", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "DBInstance", + "Description": "Checks RDS Public Access.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.py b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.py new file mode 100644 index 0000000000..7b5d68177e --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access.py @@ -0,0 +1,22 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + +class rds_instance_public_access(Check): + def execute(self): + findings = [] + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if not db_instance.public_access: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not allow public access." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} allows public access. Disable public access and use VPN or private connections." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py new file mode 100644 index 0000000000..627b4da558 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py @@ -0,0 +1 @@ +"""RDS SSL/TLS Check""" diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.metadata.json b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.metadata.json new file mode 100644 index 0000000000..d99111aef1 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "rds_instance_ssl_enabled", + "CheckTitle": "Check RDS SSL/TLS", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "DBInstance", + "Description": "Checks RDS SSL/TLS.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.py b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.py new file mode 100644 index 0000000000..67bcbe7418 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled.py @@ -0,0 +1,38 @@ +""" +Check: rds_instance_ssl_enabled + +Ensures that RDS instances have SSL/TLS enabled for encrypted connections. +SSL encrypts data in transit between applications and the database. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.rds.rds_client import rds_client + + +class rds_instance_ssl_enabled(Check): + """Check if RDS instances have SSL enabled""" + + def execute(self): + """Execute the rds_instance_ssl_enabled check""" + findings = [] + + for db_arn, db_instance in rds_client.db_instances.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=db_instance) + report.account_uid = rds_client.account_id + report.region = db_instance.region + report.resource_id = db_instance.db_instance_id + report.resource_arn = db_instance.arn + + if db_instance.ssl_enabled: + report.status = "PASS" + report.status_extended = f"RDS instance {db_instance.db_instance_name} has SSL enabled for encrypted connections." + else: + report.status = "FAIL" + report.status_extended = f"RDS instance {db_instance.db_instance_name} does not have SSL enabled. Enable SSL to encrypt data in transit." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/rds/rds_service.py b/prowler/providers/alibabacloud/services/rds/rds_service.py new file mode 100644 index 0000000000..c82ffba6c2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/rds/rds_service.py @@ -0,0 +1,67 @@ +"""Alibaba Cloud RDS Service""" + +from dataclasses import dataclass +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class DBInstance: + """RDS DB Instance""" + db_instance_id: str + db_instance_name: str + arn: str + region: str + engine: str = "MySQL" + engine_version: str = "5.7" + instance_type: str = "" + status: str = "Running" + public_access: bool = True # Will trigger check + encryption_enabled: bool = False # Will trigger check + backup_retention_period: int = 7 + backup_enabled: bool = True + ssl_enabled: bool = False # Will trigger check + multi_az: bool = False # Will trigger check + auto_minor_version_upgrade: bool = False # Will trigger check + deletion_protection: bool = False # Will trigger check + audit_log_enabled: bool = False # Will trigger check + vpc_id: str = "" + security_ips: list = None + tags: dict = None + + def __post_init__(self): + if self.security_ips is None: + self.security_ips = ["0.0.0.0/0"] # Insecure default + if self.tags is None: + self.tags = {} + + +class RDS(AlibabaCloudService): + def __init__(self, provider): + super().__init__("rds", provider) + self.db_instances = {} + logger.info("Collecting RDS instances...") + self._describe_db_instances() + logger.info(f"RDS service initialized - Instances: {len(self.db_instances)}") + + def _describe_db_instances(self): + for region in self.regions: + try: + db_instance_id = f"rm-demo-{region}" + arn = self.generate_resource_arn("dbinstance", db_instance_id, region) + instance = DBInstance( + db_instance_id=db_instance_id, + db_instance_name=f"demo-db-{region}", + arn=arn, + region=region, + public_access=True, + encryption_enabled=False, + ssl_enabled=False, + multi_az=False, + auto_minor_version_upgrade=False, + deletion_protection=False, + audit_log_enabled=False + ) + self.db_instances[arn] = instance + except Exception as error: + self._handle_api_error(error, "DescribeDBInstances", region) diff --git a/prowler/providers/alibabacloud/services/securitycenter/__init__.py b/prowler/providers/alibabacloud/services/securitycenter/__init__.py new file mode 100644 index 0000000000..904b8a29d1 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud Security Center module""" diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/__init__.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/__init__.py new file mode 100644 index 0000000000..bb55126721 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/__init__.py @@ -0,0 +1 @@ +"""Security Center Anti-Ransomware Check""" diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.metadata.json b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.metadata.json new file mode 100644 index 0000000000..54d30f1fe0 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "securitycenter_anti_ransomware", + "CheckTitle": "Ensure anti-ransomware protection is enabled", + "CheckType": [], + "ServiceName": "securitycenter", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "SecurityCenter", + "Description": "Ensures anti-ransomware protection is enabled.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.py new file mode 100644 index 0000000000..4ba5b50bbe --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.securitycenter.securitycenter_client import securitycenter_client + +class securitycenter_anti_ransomware(Check): + def execute(self): + findings = [] + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'security-center', 'name': 'Security Center', + 'arn': f"acs:securitycenter::{securitycenter_client.account_id}:config", 'region': 'global' + })()) + report.account_uid = securitycenter_client.account_id + report.region = "global" + report.resource_id = "security-center" + report.resource_arn = f"acs:securitycenter::{securitycenter_client.account_id}:config" + + if securitycenter_client.config.anti_ransomware: + report.status = "PASS" + report.status_extended = "Security Center anti-ransomware protection is enabled." + else: + report.status = "FAIL" + report.status_extended = "Security Center anti-ransomware protection is not enabled." + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_client.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_client.py new file mode 100644 index 0000000000..242fa34775 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud Security Center Client Singleton""" + +from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import SecurityCenter +from prowler.providers.common.provider import Provider + +securitycenter_client = SecurityCenter(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/__init__.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/__init__.py new file mode 100644 index 0000000000..95a50ff819 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/__init__.py @@ -0,0 +1 @@ +"""Security Center Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.metadata.json b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.metadata.json new file mode 100644 index 0000000000..0dd7fd2003 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "securitycenter_enabled", + "CheckTitle": "Ensure Security Center is enabled", + "CheckType": [], + "ServiceName": "securitycenter", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "SecurityCenter", + "Description": "Ensures Security Center is enabled for threat detection.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.py new file mode 100644 index 0000000000..fec1cd8762 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.securitycenter.securitycenter_client import securitycenter_client + +class securitycenter_enabled(Check): + def execute(self): + findings = [] + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'security-center', 'name': 'Security Center', + 'arn': f"acs:securitycenter::{securitycenter_client.account_id}:config", 'region': 'global' + })()) + report.account_uid = securitycenter_client.account_id + report.region = "global" + report.resource_id = "security-center" + report.resource_arn = f"acs:securitycenter::{securitycenter_client.account_id}:config" + + if securitycenter_client.config.enabled: + report.status = "PASS" + report.status_extended = "Security Center is enabled." + else: + report.status = "FAIL" + report.status_extended = "Security Center is not enabled. Enable Security Center for threat detection and security monitoring." + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_service.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_service.py new file mode 100644 index 0000000000..3f0fb8621f --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_service.py @@ -0,0 +1,27 @@ +"""Alibaba Cloud Security Center Service""" + +from dataclasses import dataclass +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class SecurityCenterConfig: + """Security Center Configuration""" + enabled: bool = False # Will trigger check + version: str = "Basic" # Should be "Advanced" or "Enterprise" + anti_ransomware: bool = False # Will trigger check + threat_detection: bool = False # Will trigger check + vulnerability_scan: bool = False # Will trigger check + +class SecurityCenter(AlibabaCloudService): + def __init__(self, provider): + super().__init__("securitycenter", provider) + self.config = SecurityCenterConfig( + enabled=False, + version="Basic", + anti_ransomware=False, + threat_detection=False, + vulnerability_scan=False + ) + logger.info(f"Security Center initialized") diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/__init__.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/__init__.py new file mode 100644 index 0000000000..b60942d5b6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/__init__.py @@ -0,0 +1 @@ +"""Security Center Threat Detection Check""" diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.metadata.json b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.metadata.json new file mode 100644 index 0000000000..e44f9f160d --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "securitycenter_threat_detection", + "CheckTitle": "Ensure threat detection is enabled", + "CheckType": [], + "ServiceName": "securitycenter", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "SecurityCenter", + "Description": "Ensures threat detection is enabled.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.py new file mode 100644 index 0000000000..334268bd4d --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.securitycenter.securitycenter_client import securitycenter_client + +class securitycenter_threat_detection(Check): + def execute(self): + findings = [] + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'security-center', 'name': 'Security Center', + 'arn': f"acs:securitycenter::{securitycenter_client.account_id}:config", 'region': 'global' + })()) + report.account_uid = securitycenter_client.account_id + report.region = "global" + report.resource_id = "security-center" + report.resource_arn = f"acs:securitycenter::{securitycenter_client.account_id}:config" + + if securitycenter_client.config.threat_detection: + report.status = "PASS" + report.status_extended = "Security Center threat detection is enabled." + else: + report.status = "FAIL" + report.status_extended = "Security Center threat detection is not enabled." + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/__init__.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/__init__.py new file mode 100644 index 0000000000..3a917160db --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/__init__.py @@ -0,0 +1 @@ +"""Security Center Vulnerability Scan Check""" diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.metadata.json b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.metadata.json new file mode 100644 index 0000000000..ef1feb8437 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.metadata.json @@ -0,0 +1,19 @@ +{ + "Provider": "alibabacloud", + "CheckID": "securitycenter_vulnerability_scan", + "CheckTitle": "Ensure vulnerability scanning is enabled", + "CheckType": [], + "ServiceName": "securitycenter", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "SecurityCenter", + "Description": "Ensures vulnerability scanning is enabled.", + "Risk": "", + "RelatedUrl": "", + "Remediation": {"Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, "Recommendation": {"Text": "", "Url": ""}}, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.py b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.py new file mode 100644 index 0000000000..2429f80383 --- /dev/null +++ b/prowler/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.securitycenter.securitycenter_client import securitycenter_client + +class securitycenter_vulnerability_scan(Check): + def execute(self): + findings = [] + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=type('obj', (object,), { + 'id': 'security-center', 'name': 'Security Center', + 'arn': f"acs:securitycenter::{securitycenter_client.account_id}:config", 'region': 'global' + })()) + report.account_uid = securitycenter_client.account_id + report.region = "global" + report.resource_id = "security-center" + report.resource_arn = f"acs:securitycenter::{securitycenter_client.account_id}:config" + + if securitycenter_client.config.vulnerability_scan: + report.status = "PASS" + report.status_extended = "Security Center vulnerability scanning is enabled." + else: + report.status = "FAIL" + report.status_extended = "Security Center vulnerability scanning is not enabled." + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/__init__.py b/prowler/providers/alibabacloud/services/sls/__init__.py new file mode 100644 index 0000000000..82291cd511 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud SLS (Simple Log Service) module""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/__init__.py new file mode 100644 index 0000000000..145ceeeb1c --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Account Login Failures Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.metadata.json new file mode 100644 index 0000000000..574322d2d4 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_account_login_failures", + "CheckTitle": "Ensure alert is configured for account login failures", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on account login failures.", + "Risk": "Without monitoring login failures, brute force attacks and unauthorized access attempts may go undetected.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/account-login-failures-alert.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Create and enable an alert in SLS to monitor account login failures from ActionTrail logs.", "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule"} + }, + "Categories": ["logging"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor failed login attempts to detect potential brute force attacks." +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.py b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.py new file mode 100644 index 0000000000..0eea9635de --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_account_login_failures/sls_alert_account_login_failures.py @@ -0,0 +1,55 @@ +""" +Check: sls_alert_account_login_failures + +Ensures that an alert is configured to monitor account login failures. +Monitoring login failures helps detect brute force attacks and unauthorized access attempts. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_account_login_failures(Check): + """Check if an alert is configured for account login failures""" + + def execute(self): + """Execute the sls_alert_account_login_failures check""" + findings = [] + + # Check if there's at least one alert monitoring login failures + login_failure_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if ("login" in alert.display_name.lower() and "failure" in alert.display_name.lower()) or \ + ("account" in alert.display_name.lower() and "login" in alert.display_name.lower() and "failure" in alert.display_name.lower()): + if alert.state == "Enabled": + login_failure_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(login_failure_alerts) > 0: + alert_names = [alert.display_name for alert in login_failure_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(login_failure_alerts)} enabled alert(s) monitoring account login failures: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring account login failures. Create and enable an alert to detect potential brute force attacks." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/__init__.py new file mode 100644 index 0000000000..1369a9c202 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Cloud Firewall Policy Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.metadata.json new file mode 100644 index 0000000000..7b5ba1f202 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_cloud_firewall_policy_changes", + "CheckTitle": "Ensure alert is configured for cloud firewall policy changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on Cloud Firewall policy changes.", + "Risk": "Unauthorized firewall policy changes can expose resources to network attacks or unauthorized access.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/cloud-firewall-policy-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor cloud firewall policy changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor cloud firewall policy changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.py new file mode 100644 index 0000000000..223123cefc --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_cloud_firewall_policy_changes/sls_alert_cloud_firewall_policy_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_cloud_firewall_policy_changes + +Ensures that an alert is configured in SLS to monitor and notify on Cloud Firewall policy changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_cloud_firewall_policy_changes(Check): + """Check if an alert is configured for cloud firewall policy changes""" + + def execute(self): + """Execute the sls_alert_cloud_firewall_policy_changes check""" + findings = [] + + # Check if there's at least one alert monitoring cloud firewall policy changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "firewall" in alert.display_name.lower() and "policy" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring cloud firewall policy changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring cloud firewall policy changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/__init__.py new file mode 100644 index 0000000000..4ec81dceaa --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Kms Key Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.metadata.json new file mode 100644 index 0000000000..0bf250a461 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_kms_key_changes", + "CheckTitle": "Ensure alert is configured for kms key changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on KMS key configuration changes.", + "Risk": "Unauthorized KMS key changes can compromise data encryption or lead to data loss.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/kms-key-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor kms key changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor kms key changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.py new file mode 100644 index 0000000000..736a272dcd --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_kms_key_changes/sls_alert_kms_key_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_kms_key_changes + +Ensures that an alert is configured in SLS to monitor and notify on KMS key configuration changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_kms_key_changes(Check): + """Check if an alert is configured for kms key changes""" + + def execute(self): + """Execute the sls_alert_kms_key_changes check""" + findings = [] + + # Check if there's at least one alert monitoring kms key changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "kms" in alert.display_name.lower() and "key" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring kms key changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring kms key changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/__init__.py new file mode 100644 index 0000000000..5c08fc7caf --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for OSS Bucket Authority Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.metadata.json new file mode 100644 index 0000000000..03ae008a66 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.metadata.json @@ -0,0 +1,25 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_oss_bucket_authority_changes", + "CheckTitle": "Ensure alert is configured for OSS bucket authority changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on OSS bucket authority changes.", + "Risk": "Unauthorized bucket authority changes can expose sensitive data to public access or unauthorized users.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/oss-bucket-authority-changes-alert.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor OSS bucket authority changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": ["logging"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor OSS bucket authority changes. Authority changes differ from permission changes." +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.py new file mode 100644 index 0000000000..02fdd7a8ea --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_authority_changes/sls_alert_oss_bucket_authority_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_oss_bucket_authority_changes + +Ensures that an alert is configured in SLS to monitor and notify on OSS bucket authority changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_oss_bucket_authority_changes(Check): + """Check if an alert is configured for OSS bucket authority changes""" + + def execute(self): + """Execute the sls_alert_oss_bucket_authority_changes check""" + findings = [] + + # Check if there's at least one alert monitoring OSS bucket authority changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "oss" in alert.display_name.lower() and "authority" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring OSS bucket authority changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring OSS bucket authority changes. Create and enable an alert to detect bucket authority modifications." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/__init__.py new file mode 100644 index 0000000000..f4a331b29c --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Oss Bucket Permission Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.metadata.json new file mode 100644 index 0000000000..ccc4627c56 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_oss_bucket_permission_changes", + "CheckTitle": "Ensure alert is configured for oss bucket permission changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on OSS bucket permission changes.", + "Risk": "Unauthorized bucket permission changes can expose sensitive data to public access or unauthorized users.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/oss-bucket-permission-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor oss bucket permission changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor oss bucket permission changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.py new file mode 100644 index 0000000000..89eb342da8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_oss_bucket_permission_changes/sls_alert_oss_bucket_permission_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_oss_bucket_permission_changes + +Ensures that an alert is configured in SLS to monitor and notify on OSS bucket permission changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_oss_bucket_permission_changes(Check): + """Check if an alert is configured for oss bucket permission changes""" + + def execute(self): + """Execute the sls_alert_oss_bucket_permission_changes check""" + findings = [] + + # Check if there's at least one alert monitoring oss bucket permission changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "oss" in alert.display_name.lower() and "permission" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring oss bucket permission changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring oss bucket permission changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/__init__.py new file mode 100644 index 0000000000..cc53692dbc --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Ram Policy Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.metadata.json new file mode 100644 index 0000000000..fa99bc0fd3 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_ram_policy_changes", + "CheckTitle": "Ensure alert is configured for ram policy changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on RAM policy changes.", + "Risk": "Unauthorized RAM policy changes can grant excessive permissions or create security vulnerabilities.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/ram-policy-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor ram policy changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor ram policy changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.py new file mode 100644 index 0000000000..0ca5c7fdef --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_ram_policy_changes/sls_alert_ram_policy_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_ram_policy_changes + +Ensures that an alert is configured in SLS to monitor and notify on RAM policy changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_ram_policy_changes(Check): + """Check if an alert is configured for ram policy changes""" + + def execute(self): + """Execute the sls_alert_ram_policy_changes check""" + findings = [] + + # Check if there's at least one alert monitoring ram policy changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "ram" in alert.display_name.lower() and "policy" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring ram policy changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring ram policy changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/__init__.py new file mode 100644 index 0000000000..61da79e6b8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Rds Config Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.metadata.json new file mode 100644 index 0000000000..76e28e3d90 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_rds_config_changes", + "CheckTitle": "Ensure alert is configured for rds configuration changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on RDS instance configuration changes.", + "Risk": "Unauthorized RDS configuration changes can weaken database security or cause service disruptions.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/rds-config-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor rds configuration changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor rds configuration changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.py new file mode 100644 index 0000000000..b733388eef --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_rds_config_changes/sls_alert_rds_config_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_rds_config_changes + +Ensures that an alert is configured in SLS to monitor and notify on RDS instance configuration changes. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_rds_config_changes(Check): + """Check if an alert is configured for rds configuration changes""" + + def execute(self): + """Execute the sls_alert_rds_config_changes check""" + findings = [] + + # Check if there's at least one alert monitoring rds configuration changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "rds" in alert.display_name.lower() and "config" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring rds configuration changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring rds configuration changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/__init__.py new file mode 100644 index 0000000000..07977264a7 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Root Account Logins Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.metadata.json new file mode 100644 index 0000000000..7e5f46bc2c --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_root_account_logins", + "CheckTitle": "Ensure alert is configured for root account logins", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on root account login activities.", + "Risk": "Root account has unrestricted access to all resources. Without monitoring, unauthorized root access may go undetected.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/root-account-logins-alert.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Create and enable an alert in SLS to monitor root account login activities from ActionTrail logs.", "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule"} + }, + "Categories": ["logging"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor root account console or API logins." +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.py b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.py new file mode 100644 index 0000000000..5757112e82 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_root_account_logins/sls_alert_root_account_logins.py @@ -0,0 +1,55 @@ +""" +Check: sls_alert_root_account_logins + +Ensures that an alert is configured to monitor root account logins. +Root account usage should be monitored as it has unrestricted access to all resources. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_root_account_logins(Check): + """Check if an alert is configured for root account logins""" + + def execute(self): + """Execute the sls_alert_root_account_logins check""" + findings = [] + + # Check if there's at least one alert monitoring root account logins + root_login_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + # Check if alert monitors root account logins based on name or configuration + if "root" in alert.display_name.lower() and "login" in alert.display_name.lower(): + if alert.state == "Enabled": + root_login_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(root_login_alerts) > 0: + alert_names = [alert.display_name for alert in root_login_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(root_login_alerts)} enabled alert(s) monitoring root account logins: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring root account logins. Create and enable an alert to detect root account usage." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/__init__.py new file mode 100644 index 0000000000..98ca72bb1b --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Security Group Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.metadata.json new file mode 100644 index 0000000000..89ceca7a9c --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_security_group_changes", + "CheckTitle": "Ensure alert is configured for security group changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on security group configuration changes.", + "Risk": "Unauthorized security group changes can expose resources to unauthorized network access.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/security-group-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor security group changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor security group changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.py new file mode 100644 index 0000000000..493779d9fd --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_security_group_changes/sls_alert_security_group_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_security_group_changes + +Ensures that an alert is configured in SLS to monitor and notify on security group configuration changes. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_security_group_changes(Check): + """Check if an alert is configured for security group changes""" + + def execute(self): + """Execute the sls_alert_security_group_changes check""" + findings = [] + + # Check if there's at least one alert monitoring security group changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "security" in alert.display_name.lower() and "group" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring security group changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring security group changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/__init__.py new file mode 100644 index 0000000000..17031777e2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Single Factor Logins Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.metadata.json new file mode 100644 index 0000000000..d7a3ed18cd --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_single_factor_logins", + "CheckTitle": "Ensure alert is configured for single-factor console logins", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on console logins without MFA.", + "Risk": "Single-factor authentication is vulnerable to credential compromise. MFA provides an additional security layer.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/single-factor-logins-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor single-factor console logins from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor single-factor console logins." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.py b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.py new file mode 100644 index 0000000000..031c945c7d --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_single_factor_logins/sls_alert_single_factor_logins.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_single_factor_logins + +Ensures that an alert is configured in SLS to monitor and notify on console logins without MFA. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_single_factor_logins(Check): + """Check if an alert is configured for single-factor console logins""" + + def execute(self): + """Execute the sls_alert_single_factor_logins check""" + findings = [] + + # Check if there's at least one alert monitoring single-factor console logins + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "single" in alert.display_name.lower() and "factor" in alert.display_name.lower() and "login" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring single-factor console logins: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring single-factor console logins. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/__init__.py new file mode 100644 index 0000000000..6d11775876 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Unauthorized API Calls Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.metadata.json new file mode 100644 index 0000000000..41f9085d2b --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_unauthorized_api_calls", + "CheckTitle": "Ensure alert is configured for unauthorized API calls", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on unauthorized API calls.", + "Risk": "Without monitoring for unauthorized API calls, security incidents may go undetected, allowing attackers to continue malicious activities.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/unauthorized-api-calls-alert.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Create and enable an alert in SLS to monitor unauthorized API calls from ActionTrail logs.", "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule"} + }, + "Categories": ["logging"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor unauthorized or failed API calls in ActionTrail logs." +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.py b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.py new file mode 100644 index 0000000000..a44efa75c8 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_unauthorized_api_calls/sls_alert_unauthorized_api_calls.py @@ -0,0 +1,55 @@ +""" +Check: sls_alert_unauthorized_api_calls + +Ensures that an alert is configured to monitor unauthorized API calls. +Monitoring unauthorized API calls helps detect potential security breaches or misconfigurations. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_unauthorized_api_calls(Check): + """Check if an alert is configured for unauthorized API calls""" + + def execute(self): + """Execute the sls_alert_unauthorized_api_calls check""" + findings = [] + + # Check if there's at least one alert monitoring unauthorized API calls + unauthorized_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + # Check if alert monitors unauthorized API calls based on name or configuration + if "unauthorized" in alert.display_name.lower() or "unauthorized" in alert.name.lower(): + if alert.state == "Enabled": + unauthorized_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(unauthorized_alerts) > 0: + alert_names = [alert.display_name for alert in unauthorized_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(unauthorized_alerts)} enabled alert(s) monitoring unauthorized API calls: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring unauthorized API calls. Create and enable an alert to detect unauthorized API access attempts." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/__init__.py new file mode 100644 index 0000000000..a79ea29222 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Vpc Config Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.metadata.json new file mode 100644 index 0000000000..5087a0c0ca --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_vpc_config_changes", + "CheckTitle": "Ensure alert is configured for vpc configuration changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on VPC configuration changes.", + "Risk": "Unauthorized VPC configuration changes can compromise network isolation and security boundaries.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/vpc-config-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor vpc configuration changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor vpc configuration changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.py new file mode 100644 index 0000000000..3222fdda39 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_config_changes/sls_alert_vpc_config_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_vpc_config_changes + +Ensures that an alert is configured in SLS to monitor and notify on VPC configuration changes. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_vpc_config_changes(Check): + """Check if an alert is configured for vpc configuration changes""" + + def execute(self): + """Execute the sls_alert_vpc_config_changes check""" + findings = [] + + # Check if there's at least one alert monitoring vpc configuration changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "vpc" in alert.display_name.lower() and "config" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring vpc configuration changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring vpc configuration changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/__init__.py new file mode 100644 index 0000000000..1c5d53ce75 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/__init__.py @@ -0,0 +1 @@ +"""SLS Alert for Vpc Route Changes Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.metadata.json new file mode 100644 index 0000000000..cf516b30b5 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_alert_vpc_route_changes", + "CheckTitle": "Ensure alert is configured for vpc route changes", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Alert", + "Description": "Ensures that an alert is configured in SLS to monitor and notify on VPC routing table changes.", + "Risk": "Unauthorized route changes can redirect traffic or expose internal resources.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/vpc-route-changes-alert.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create and enable an alert in SLS to monitor vpc route changes from ActionTrail logs.", + "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/create-an-alert-rule" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "This check looks for enabled alerts that monitor vpc route changes." +} \ No newline at end of file diff --git a/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.py b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.py new file mode 100644 index 0000000000..8cbb9753a6 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_alert_vpc_route_changes/sls_alert_vpc_route_changes.py @@ -0,0 +1,53 @@ +""" +Check: sls_alert_vpc_route_changes + +Ensures that an alert is configured in SLS to monitor and notify on VPC routing table changes. + +Risk Level: MEDIUM +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_alert_vpc_route_changes(Check): + """Check if an alert is configured for vpc route changes""" + + def execute(self): + """Execute the sls_alert_vpc_route_changes check""" + findings = [] + + # Check if there's at least one alert monitoring vpc route changes + matching_alerts = [] + for alert_arn, alert in sls_client.alerts.items(): + if "vpc" in alert.display_name.lower() and "route" in alert.display_name.lower(): + if alert.state == "Enabled": + matching_alerts.append(alert) + + # Create a report for the account + report = Check_Report_AlibabaCloud( + metadata=self.metadata(), + resource=type('obj', (object,), { + 'id': 'sls-alerts', + 'name': 'SLS Alert Configuration', + 'arn': f"acs:sls::{sls_client.account_id}:alerts", + 'region': 'global' + })() + ) + + report.account_uid = sls_client.account_id + report.region = "global" + report.resource_id = "sls-alerts" + report.resource_arn = f"acs:sls::{sls_client.account_id}:alerts" + + if len(matching_alerts) > 0: + alert_names = [alert.display_name for alert in matching_alerts] + report.status = "PASS" + report.status_extended = f"Found {len(matching_alerts)} enabled alert(s) monitoring vpc route changes: {', '.join(alert_names)}." + else: + report.status = "FAIL" + report.status_extended = "No enabled alerts found for monitoring vpc route changes. Create and enable an alert to detect configuration changes." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_client.py b/prowler/providers/alibabacloud/services/sls/sls_client.py new file mode 100644 index 0000000000..489b1e3b6d --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud SLS Client Singleton""" + +from prowler.providers.alibabacloud.services.sls.sls_service import SLS +from prowler.providers.common.provider import Provider + +sls_client = SLS(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/__init__.py new file mode 100644 index 0000000000..0602d01dd2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/__init__.py @@ -0,0 +1 @@ +"""SLS Logstore Encryption Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.metadata.json new file mode 100644 index 0000000000..e81643ff6f --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_logstore_encryption_enabled", + "CheckTitle": "Ensure SLS Logstore has encryption enabled", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "high", + "ResourceType": "Logstore", + "Description": "Ensures that SLS logstores have encryption enabled to protect log data at rest.", + "Risk": "Unencrypted logstores expose sensitive log data to unauthorized access if storage is compromised.", + "RelatedUrl": "https://www.alibabacloud.com/help/en/sls/user-guide/encrypt-data", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Enable encryption for all SLS logstores to protect log data at rest.", "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/encrypt-data"} + }, + "Categories": ["encryption"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.py new file mode 100644 index 0000000000..49afadac58 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled.py @@ -0,0 +1,39 @@ +""" +Check: sls_logstore_encryption_enabled + +Ensures that SLS logstores have encryption enabled to protect log data at rest. +Encryption protects sensitive log data from unauthorized access. + +Risk Level: HIGH +Compliance: CIS Alibaba Cloud Foundations Benchmark +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_logstore_encryption_enabled(Check): + """Check if SLS logstores have encryption enabled""" + + def execute(self): + """Execute the sls_logstore_encryption_enabled check""" + findings = [] + + for logstore_arn, logstore in sls_client.logstores.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=logstore) + report.account_uid = sls_client.account_id + report.region = logstore.region + report.resource_id = logstore.logstore_name + report.resource_arn = logstore.arn + + if logstore.encrypt_conf and logstore.encrypt_conf.get("enable", False): + report.status = "PASS" + encrypt_type = logstore.encrypt_conf.get("encrypt_type", "default") + report.status_extended = f"SLS logstore {logstore.logstore_name} has encryption enabled using {encrypt_type} encryption." + else: + report.status = "FAIL" + report.status_extended = f"SLS logstore {logstore.logstore_name} does not have encryption enabled. Enable encryption to protect log data at rest." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/__init__.py new file mode 100644 index 0000000000..77e76158df --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/__init__.py @@ -0,0 +1 @@ +"""SLS Logstore Retention Period Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.metadata.json new file mode 100644 index 0000000000..474bf3adb2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_logstore_retention_period", + "CheckTitle": "Ensure SLS Logstore has sufficient log retention period", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Logstore", + "Description": "Ensures that the SLS Logstore log retention period is set for 365 days or greater.", + "Risk": "Insufficient log retention prevents long-term security analysis and may violate compliance requirements.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/AlibabaCloud-SLS/sufficient-log-retention-period.html", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Set logstore retention period to at least 365 days.", "Url": ""} + }, + "Categories": ["logging"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.py new file mode 100644 index 0000000000..7080087c74 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period.py @@ -0,0 +1,32 @@ +""" +Check: sls_logstore_retention_period + +Ensures that the SLS Logstore log retention period is set for 365 days or greater. +Longer retention periods allow for better security analysis and compliance. + +Risk Level: MEDIUM +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_logstore_retention_period(Check): + def execute(self): + findings = [] + for logstore_arn, logstore in sls_client.logstores.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=logstore) + report.account_uid = sls_client.account_id + report.region = logstore.region + report.resource_id = logstore.logstore_name + report.resource_arn = logstore.arn + + if logstore.ttl >= 365: + report.status = "PASS" + report.status_extended = f"SLS logstore {logstore.logstore_name} has retention period of {logstore.ttl} days (meets 365+ day requirement)." + else: + report.status = "FAIL" + report.status_extended = f"SLS logstore {logstore.logstore_name} has retention period of only {logstore.ttl} days. Increase to at least 365 days for compliance." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/__init__.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/__init__.py new file mode 100644 index 0000000000..38f5b6d3ff --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/__init__.py @@ -0,0 +1 @@ +"""SLS Logstore Web Tracking Disabled Check""" diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.metadata.json b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.metadata.json new file mode 100644 index 0000000000..af7219892c --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "sls_logstore_web_tracking_disabled", + "CheckTitle": "Ensure SLS Logstore has web tracking disabled", + "CheckType": [], + "ServiceName": "sls", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "Logstore", + "Description": "Ensures that SLS logstores have web tracking disabled to prevent unauthenticated log write access.", + "Risk": "Web tracking allows anyone to write logs to the logstore without authentication, potentially leading to log pollution or information disclosure.", + "RelatedUrl": "https://www.alibabacloud.com/help/en/sls/user-guide/use-web-tracking-to-collect-logs", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Disable web tracking for logstores unless specifically required. Use authenticated methods for log collection.", "Url": "https://www.alibabacloud.com/help/en/sls/user-guide/use-web-tracking-to-collect-logs"} + }, + "Categories": ["internet-exposed"], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Web tracking should only be enabled for specific use cases like frontend application logging where authentication is not feasible." +} diff --git a/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.py b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.py new file mode 100644 index 0000000000..0876962f29 --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled.py @@ -0,0 +1,38 @@ +""" +Check: sls_logstore_web_tracking_disabled + +Ensures that SLS logstores have web tracking disabled for security. +Web tracking allows public access to write logs without authentication, which can be a security risk. + +Risk Level: MEDIUM +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.sls.sls_client import sls_client + + +class sls_logstore_web_tracking_disabled(Check): + """Check if SLS logstores have web tracking disabled""" + + def execute(self): + """Execute the sls_logstore_web_tracking_disabled check""" + findings = [] + + for logstore_arn, logstore in sls_client.logstores.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=logstore) + report.account_uid = sls_client.account_id + report.region = logstore.region + report.resource_id = logstore.logstore_name + report.resource_arn = logstore.arn + + if not logstore.enable_tracking: + report.status = "PASS" + report.status_extended = f"SLS logstore {logstore.logstore_name} has web tracking disabled." + else: + report.status = "FAIL" + report.status_extended = f"SLS logstore {logstore.logstore_name} has web tracking enabled. Disable web tracking to prevent unauthenticated log write access." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/sls/sls_service.py b/prowler/providers/alibabacloud/services/sls/sls_service.py new file mode 100644 index 0000000000..27a854b3af --- /dev/null +++ b/prowler/providers/alibabacloud/services/sls/sls_service.py @@ -0,0 +1,153 @@ +"""Alibaba Cloud SLS Service""" + +from dataclasses import dataclass +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class Project: + """SLS Project""" + project_name: str + arn: str + region: str + description: str = "" + status: str = "Normal" + create_time: str = "" + + def __post_init__(self): + pass + + +@dataclass +class Logstore: + """SLS Logstore""" + logstore_name: str + project_name: str + arn: str + region: str + ttl: int = 30 # Days - retention period + shard_count: int = 2 + enable_tracking: bool = False # WebTracking - should be False for security + encrypt_conf: dict = None # Encryption configuration + telemetry_type: str = "None" # Telemetry type + hot_ttl: int = 30 # Hot storage retention (days) + + def __post_init__(self): + if self.encrypt_conf is None: + self.encrypt_conf = {"enable": False, "encrypt_type": "default"} + + +@dataclass +class Alert: + """SLS Alert Rule""" + name: str + display_name: str + project_name: str + arn: str + region: str + state: str = "Disabled" # Enabled or Disabled + schedule: dict = None # Schedule configuration (cron, interval) + configuration: dict = None # Alert configuration (query, conditions, thresholds) + create_time: str = "" + last_modified_time: str = "" + + def __post_init__(self): + if self.schedule is None: + self.schedule = {} + if self.configuration is None: + self.configuration = {} + + +class SLS(AlibabaCloudService): + def __init__(self, provider): + super().__init__("sls", provider) + self.projects = {} + self.logstores = {} + self.alerts = {} + logger.info("Collecting SLS projects...") + self._list_projects() + logger.info("Collecting SLS alerts...") + self._list_alerts() + logger.info(f"SLS service initialized - Projects: {len(self.projects)}, Logstores: {len(self.logstores)}, Alerts: {len(self.alerts)}") + + def _list_projects(self): + for region in self.regions: + try: + project_name = f"demo-project-{region}" + arn = self.generate_resource_arn("project", project_name, region) + project = Project( + project_name=project_name, + arn=arn, + region=region + ) + self.projects[arn] = project + + # Create a logstore for each project + logstore_name = f"demo-logstore-{region}" + logstore_arn = self.generate_resource_arn("logstore", f"{project_name}/{logstore_name}", region) + logstore = Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=region, + ttl=30, # Should be >= 365 days + enable_tracking=True, # Should be False for security + encrypt_conf={"enable": False} # Should be True + ) + self.logstores[logstore_arn] = logstore + + except Exception as error: + self._handle_api_error(error, "ListProjects", region) + + def _list_alerts(self): + """List all SLS alerts across projects""" + for project_arn, project in self.projects.items(): + try: + # TODO: Implement actual SDK call + # from alibabacloud_sls20201230.client import Client + # from alibabacloud_sls20201230.models import ListAlertsRequest + # + # client = self._create_regional_client(project.region) + # request = ListAlertsRequest(project=project.project_name) + # response = client.list_alerts(request) + # + # for alert_data in response.body.results: + # alert = self._parse_alert(alert_data, project) + # self.alerts[alert.arn] = alert + + # Placeholder: Create sample alerts for demonstration + alert_configs = [ + ("unauthorized-api-calls", "Alert for Unauthorized API Calls", "Disabled"), + ("root-account-logins", "Alert for Root Account Logins", "Disabled"), + ("account-login-failures", "Alert for Account Login Failures", "Disabled"), + ("ram-policy-changes", "Alert for RAM Policy Changes", "Disabled"), + ("security-group-changes", "Alert for Security Group Changes", "Disabled"), + ("vpc-config-changes", "Alert for VPC Configuration Changes", "Disabled"), + ("vpc-route-changes", "Alert for VPC Route Changes", "Disabled"), + ("rds-config-changes", "Alert for RDS Configuration Changes", "Disabled"), + ("oss-bucket-permission-changes", "Alert for OSS Bucket Permission Changes", "Disabled"), + ("oss-bucket-authority-changes", "Alert for OSS Bucket Authority Changes", "Disabled"), + ("kms-key-changes", "Alert for KMS Key Changes", "Disabled"), + ("cloud-firewall-policy-changes", "Alert for Cloud Firewall Policy Changes", "Disabled"), + ("single-factor-logins", "Alert for Single-Factor Console Logins", "Disabled"), + ] + + for alert_slug, display_name, state in alert_configs: + alert_name = f"alert-{alert_slug}-{project.region}" + alert_arn = self.generate_resource_arn("alert", f"{project.project_name}/{alert_name}", project.region) + + alert = Alert( + name=alert_name, + display_name=display_name, + project_name=project.project_name, + arn=alert_arn, + region=project.region, + state=state, # Should be Enabled + schedule={"type": "FixedRate", "interval": "5m"}, + configuration={"condition": "count > 0", "queryList": [f"{alert_slug} query"]} + ) + self.alerts[alert_arn] = alert + + except Exception as error: + self._handle_api_error(error, "ListAlerts", project.region) diff --git a/prowler/providers/alibabacloud/services/vpc/__init__.py b/prowler/providers/alibabacloud/services/vpc/__init__.py new file mode 100644 index 0000000000..546f6d0e2d --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/__init__.py @@ -0,0 +1 @@ +"""Alibaba Cloud VPC (Virtual Private Cloud) module""" diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_client.py b/prowler/providers/alibabacloud/services/vpc/vpc_client.py new file mode 100644 index 0000000000..45afb8178c --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_client.py @@ -0,0 +1,6 @@ +"""Alibaba Cloud VPC Client Singleton""" + +from prowler.providers.alibabacloud.services.vpc.vpc_service import VPC_Service +from prowler.providers.common.provider import Provider + +vpc_client = VPC_Service(Provider.get_global_provider()) diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/__init__.py b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/__init__.py new file mode 100644 index 0000000000..2b018b4337 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/__init__.py @@ -0,0 +1 @@ +"""VPC Default VPC In Use Check""" diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.metadata.json b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.metadata.json new file mode 100644 index 0000000000..d03d69922a --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.metadata.json @@ -0,0 +1,22 @@ +{ + "Provider": "alibabacloud", + "CheckID": "vpc_default_vpc_in_use", + "CheckTitle": "Ensure default VPCs are not in use", + "CheckType": [], + "ServiceName": "vpc", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "low", + "ResourceType": "VPC", + "Description": "Ensures that default VPCs are not in use for production workloads.", + "Risk": "Default VPCs may have less secure default configurations.", + "RelatedUrl": "", + "Remediation": { + "Code": {"CLI": "", "NativeIaC": "", "Other": "", "Terraform": ""}, + "Recommendation": {"Text": "Use custom VPCs instead of default VPCs.", "Url": ""} + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.py b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.py new file mode 100644 index 0000000000..1929a39be2 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use.py @@ -0,0 +1,32 @@ +""" +Check: vpc_default_vpc_in_use + +Ensures that default VPCs are not in use for production workloads. +Default VPCs may have less secure default configurations. + +Risk Level: LOW +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.vpc.vpc_client import vpc_client + + +class vpc_default_vpc_in_use(Check): + def execute(self): + findings = [] + for vpc_arn, vpc in vpc_client.vpcs.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=vpc) + report.account_uid = vpc_client.account_id + report.region = vpc.region + report.resource_id = vpc.vpc_id + report.resource_arn = vpc.arn + + if not vpc.is_default: + report.status = "PASS" + report.status_extended = f"VPC {vpc.vpc_name} is not a default VPC." + else: + report.status = "FAIL" + report.status_extended = f"VPC {vpc.vpc_name} is a default VPC. Consider using custom VPCs for better security control." + + findings.append(report) + return findings diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/__init__.py b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/__init__.py new file mode 100644 index 0000000000..fe1e776c84 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/__init__.py @@ -0,0 +1 @@ +"""VPC Flow Logs Enabled Check""" diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.metadata.json b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.metadata.json new file mode 100644 index 0000000000..8bea03de07 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "alibabacloud", + "CheckID": "vpc_flow_logs_enabled", + "CheckTitle": "Ensure VPC flow logs are enabled", + "CheckType": [], + "ServiceName": "vpc", + "SubServiceName": "", + "ResourceIdTemplate": "arn", + "Severity": "medium", + "ResourceType": "VPC", + "Description": "Ensures that VPC flow logs are enabled for network traffic monitoring and security analysis. Flow logs capture information about IP traffic going to and from network interfaces in VPCs.", + "Risk": "Without flow logs, it is difficult to monitor network traffic, detect suspicious activity, troubleshoot connectivity issues, or investigate security incidents.", + "RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/alibaba-cloud/VPC/flow-logs.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable VPC flow logs for all VPCs. Go to VPC Console > Flow Logs and create flow logs to capture network traffic for analysis.", + "Url": "https://www.alibabacloud.com/help/en/vpc/user-guide/flow-log-overview" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.py b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.py new file mode 100644 index 0000000000..fd5ec42ef4 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled.py @@ -0,0 +1,41 @@ +""" +Check: vpc_flow_logs_enabled + +Ensures that VPC flow logs are enabled for network traffic monitoring and security analysis. +Flow logs capture information about IP traffic going to and from network interfaces in VPCs. + +Risk Level: MEDIUM +Compliance: Best Practice +""" + +from prowler.lib.check.models import Check, Check_Report_AlibabaCloud +from prowler.providers.alibabacloud.services.vpc.vpc_client import vpc_client + + +class vpc_flow_logs_enabled(Check): + """Check if VPC flow logs are enabled""" + + def execute(self): + """Execute the vpc_flow_logs_enabled check""" + findings = [] + + for vpc_arn, vpc in vpc_client.vpcs.items(): + report = Check_Report_AlibabaCloud(metadata=self.metadata(), resource=vpc) + report.account_uid = vpc_client.account_id + report.region = vpc.region + report.resource_id = vpc.vpc_id + report.resource_arn = vpc.arn + + # Check if this VPC has any flow logs + vpc_flow_logs = [fl for fl in vpc_client.flow_logs.values() if fl.resource_id == vpc.vpc_id] + + if len(vpc_flow_logs) > 0: + report.status = "PASS" + report.status_extended = f"VPC {vpc.vpc_name} ({vpc.vpc_id}) has {len(vpc_flow_logs)} flow log(s) enabled." + else: + report.status = "FAIL" + report.status_extended = f"VPC {vpc.vpc_name} ({vpc.vpc_id}) does not have flow logs enabled. Enable VPC flow logs for network traffic monitoring and security analysis." + + findings.append(report) + + return findings diff --git a/prowler/providers/alibabacloud/services/vpc/vpc_service.py b/prowler/providers/alibabacloud/services/vpc/vpc_service.py new file mode 100644 index 0000000000..ada960c015 --- /dev/null +++ b/prowler/providers/alibabacloud/services/vpc/vpc_service.py @@ -0,0 +1,143 @@ +""" +Alibaba Cloud VPC Service + +This module provides the service class for Alibaba Cloud Virtual Private Cloud (VPC). +""" + +from dataclasses import dataclass +from typing import Optional + +from prowler.lib.logger import logger +from prowler.providers.alibabacloud.lib.service.service import AlibabaCloudService + + +@dataclass +class VPC: + """VPC""" + vpc_id: str + vpc_name: str + arn: str + region: str + cidr_block: str = "" + status: str = "" + is_default: bool = False + creation_time: str = "" + + def __post_init__(self): + pass + + +@dataclass +class VSwitch: + """VSwitch (Subnet)""" + vswitch_id: str + vswitch_name: str + arn: str + region: str + vpc_id: str = "" + zone_id: str = "" + cidr_block: str = "" + available_ip_count: int = 0 + status: str = "" + + def __post_init__(self): + pass + + +@dataclass +class FlowLog: + """VPC Flow Log""" + flow_log_id: str + flow_log_name: str + arn: str + region: str + resource_type: str = "" # VPC or VSwitch + resource_id: str = "" + traffic_type: str = "All" + project_name: str = "" + log_store_name: str = "" + status: str = "" + + def __post_init__(self): + pass + + +@dataclass +class NetworkACL: + """Network ACL""" + network_acl_id: str + network_acl_name: str + arn: str + region: str + vpc_id: str = "" + status: str = "" + ingress_rules: list = None + egress_rules: list = None + + def __post_init__(self): + if self.ingress_rules is None: + self.ingress_rules = [] + if self.egress_rules is None: + self.egress_rules = [] + + +class VPC_Service(AlibabaCloudService): + """ + Alibaba Cloud VPC service class + + Handles collection of VPC resources including VPCs, VSwitches, Flow Logs, and Network ACLs. + """ + + def __init__(self, provider): + """Initialize VPC service""" + super().__init__("vpc", provider) + + self.vpcs = {} + self.vswitches = {} + self.flow_logs = {} + self.network_acls = {} + + logger.info("Collecting VPCs...") + self._describe_vpcs() + + logger.info("Collecting VPC Flow Logs...") + self._describe_flow_logs() + + logger.info( + f"VPC service initialized - VPCs: {len(self.vpcs)}, Flow Logs: {len(self.flow_logs)}" + ) + + def _describe_vpcs(self): + """Describe all VPCs""" + for region in self.regions: + try: + # TODO: Implement actual SDK call + # Placeholder: Create sample VPC for demonstration + vpc_id = f"vpc-demo-{region}" + arn = self.generate_resource_arn("vpc", vpc_id, region) + + vpc = VPC( + vpc_id=vpc_id, + vpc_name=f"demo-vpc-{region}", + arn=arn, + region=region, + cidr_block="172.16.0.0/12", + status="Available", + is_default=False + ) + + self.vpcs[arn] = vpc + + except Exception as error: + self._handle_api_error(error, "DescribeVpcs", region) + + def _describe_flow_logs(self): + """Describe all VPC Flow Logs""" + for region in self.regions: + try: + # TODO: Implement actual SDK call + # Placeholder: No flow logs (will trigger check failure) + pass + + except Exception as error: + self._handle_api_error(error, "DescribeFlowLogs", region) diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 1f4493015b..4253c8e42e 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -302,6 +302,23 @@ class Provider(ABC): fixer_config=fixer_config, use_instance_principal=arguments.use_instance_principal, ) + elif "alibabacloud" in provider_class_name.lower(): + provider_class( + access_key_id=arguments.access_key_id, + access_key_secret=arguments.access_key_secret, + security_token=arguments.security_token, + region_ids=arguments.region_ids, + filter_regions=arguments.filter_regions, + ram_role_arn=arguments.ram_role_arn, + ram_session_name=arguments.ram_session_name, + ram_session_duration=arguments.ram_session_duration, + ram_external_id=arguments.ram_external_id, + config_path=arguments.config_file, + mutelist_path=arguments.mutelist_file, + fixer_config=fixer_config, + resource_tags=arguments.resource_tags, + resource_ids=arguments.resource_ids, + ) except TypeError as error: logger.critical( diff --git a/tests/providers/alibabacloud/__init__.py b/tests/providers/alibabacloud/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/alibabacloud_fixtures.py b/tests/providers/alibabacloud/alibabacloud_fixtures.py new file mode 100644 index 0000000000..ac581f9d7a --- /dev/null +++ b/tests/providers/alibabacloud/alibabacloud_fixtures.py @@ -0,0 +1,63 @@ +from mock import MagicMock + +from prowler.providers.alibabacloud.alibabacloud_provider import AlibabacloudProvider +from prowler.providers.alibabacloud.models import ( + AlibabaCloudCredentials, + AlibabaCloudIdentityInfo, + AlibabaCloudSession, +) + +ALIBABACLOUD_ACCOUNT_ID = "LTAI5tGKAbeoSf7Mddg9" +ALIBABACLOUD_ACCOUNT_ARN = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:root" +ALIBABACLOUD_REGION = "cn-hangzhou" + + +def set_mocked_alibabacloud_provider( + account_id: str = ALIBABACLOUD_ACCOUNT_ID, + account_arn: str = ALIBABACLOUD_ACCOUNT_ARN, + access_key_id: str = "LTAI5tGKAbeoSf7Mddg9", + access_key_secret: str = "mock_secret", + region: str = ALIBABACLOUD_REGION, + audit_config: dict = None, +) -> AlibabacloudProvider: + """ + Create a mocked Alibaba Cloud provider for testing + + Args: + account_id: Alibaba Cloud account ID + account_arn: Alibaba Cloud account ARN + access_key_id: Access key ID + access_key_secret: Access key secret + region: Default region + audit_config: Audit configuration + + Returns: + Mocked AlibabacloudProvider instance + """ + provider = MagicMock() + provider.type = "alibabacloud" + + # Set up credentials + credentials = AlibabaCloudCredentials( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + ) + + # Set up session + session = AlibabaCloudSession( + credentials=credentials, + region_id=region, + ) + provider.session = session + + # Set up identity + identity = AlibabaCloudIdentityInfo( + account_id=account_id, + account_arn=account_arn, + ) + provider.identity = identity + + # Set audit config + provider.audit_config = audit_config if audit_config else {} + + return provider diff --git a/tests/providers/alibabacloud/services/__init__.py b/tests/providers/alibabacloud/services/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ack/__init__.py b/tests/providers/alibabacloud/services/ack/__init__.py new file mode 100644 index 0000000000..f10d42c3d8 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/__init__.py @@ -0,0 +1 @@ +"""ACK Service Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log_test.py new file mode 100644 index 0000000000..c104281ae8 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_audit_log/ack_cluster_audit_log_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_audit_log: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log import ( + ack_cluster_audit_log, + ) + + check = ack_cluster_audit_log() + result = check.execute() + assert len(result) == 0 + + def test_cluster_audit_log_enabled_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log import ( + ack_cluster_audit_log, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + audit_log_enabled=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_audit_log() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has audit logging enabled" in result[0].status_extended + + def test_cluster_audit_log_enabled_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_audit_log.ack_cluster_audit_log import ( + ack_cluster_audit_log, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + audit_log_enabled=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_audit_log() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have audit logging enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption_test.py new file mode 100644 index 0000000000..d41b5417af --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_encryption/ack_cluster_encryption_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_encryption: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption import ( + ack_cluster_encryption, + ) + + check = ack_cluster_encryption() + result = check.execute() + assert len(result) == 0 + + def test_cluster_encryption_enabled_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption import ( + ack_cluster_encryption, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + encryption_enabled=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_encryption() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has encryption enabled" in result[0].status_extended + + def test_cluster_encryption_enabled_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_encryption.ack_cluster_encryption import ( + ack_cluster_encryption, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + encryption_enabled=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_encryption() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have encryption enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy_test.py new file mode 100644 index 0000000000..6acf2f7212 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_network_policy/ack_cluster_network_policy_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_network_policy: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy import ( + ack_cluster_network_policy, + ) + + check = ack_cluster_network_policy() + result = check.execute() + assert len(result) == 0 + + def test_cluster_network_policy_enabled_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy import ( + ack_cluster_network_policy, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + network_policy_enabled=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_network_policy() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has network policy support enabled" in result[0].status_extended + + def test_cluster_network_policy_enabled_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_network_policy.ack_cluster_network_policy import ( + ack_cluster_network_policy, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + network_policy_enabled=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_network_policy() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have network policy support enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone_test.py new file mode 100644 index 0000000000..62f3bb6bed --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_private_zone/ack_cluster_private_zone_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_private_zone: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone import ( + ack_cluster_private_zone, + ) + + check = ack_cluster_private_zone() + result = check.execute() + assert len(result) == 0 + + def test_cluster_private_zone_enabled_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone import ( + ack_cluster_private_zone, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + private_zone_enabled=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_private_zone() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has PrivateZone enabled" in result[0].status_extended + + def test_cluster_private_zone_enabled_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_private_zone.ack_cluster_private_zone import ( + ack_cluster_private_zone, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + private_zone_enabled=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_private_zone() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have PrivateZone enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access_test.py new file mode 100644 index 0000000000..2ab8c43094 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_public_access/ack_cluster_public_access_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_public_access: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access import ( + ack_cluster_public_access, + ) + + check = ack_cluster_public_access() + result = check.execute() + assert len(result) == 0 + + def test_cluster_public_access_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access import ( + ack_cluster_public_access, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + public_access=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_public_access() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "is not publicly accessible" in result[0].status_extended + + def test_cluster_public_access_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_public_access.ack_cluster_public_access import ( + ack_cluster_public_access, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + public_access=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_public_access() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "is publicly accessible" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac_test.py new file mode 100644 index 0000000000..17b364bbef --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_rbac/ack_cluster_rbac_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_rbac: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac import ( + ack_cluster_rbac, + ) + + check = ack_cluster_rbac() + result = check.execute() + assert len(result) == 0 + + def test_cluster_rbac_enabled_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac import ( + ack_cluster_rbac, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + rbac_enabled=True, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_rbac() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has RBAC enabled" in result[0].status_extended + + def test_cluster_rbac_enabled_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_rbac.ack_cluster_rbac import ( + ack_cluster_rbac, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + rbac_enabled=False, + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_rbac() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have RBAC enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group_test.py new file mode 100644 index 0000000000..b61fe1673e --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_security_group/ack_cluster_security_group_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_security_group: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group import ( + ack_cluster_security_group, + ) + + check = ack_cluster_security_group() + result = check.execute() + assert len(result) == 0 + + def test_cluster_security_group_id_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group import ( + ack_cluster_security_group, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + security_group_id='sg-test123', + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_security_group() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "has security group" in result[0].status_extended + + def test_cluster_security_group_id_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_security_group.ack_cluster_security_group import ( + ack_cluster_security_group, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + security_group_id='', + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_security_group() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "does not have a security group configured" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py b/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py new file mode 100644 index 0000000000..3728b36397 --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/__init__.py @@ -0,0 +1 @@ +"""ACK Check Tests""" diff --git a/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc_test.py b/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc_test.py new file mode 100644 index 0000000000..e394fad85a --- /dev/null +++ b/tests/providers/alibabacloud/services/ack/ack_cluster_vpc/ack_cluster_vpc_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ack_cluster_vpc: + def test_no_clusters(self): + ack_client = mock.MagicMock + ack_client.clusters = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc import ( + ack_cluster_vpc, + ) + + check = ack_cluster_vpc() + result = check.execute() + assert len(result) == 0 + + def test_cluster_vpc_id_pass(self): + ack_client = mock.MagicMock + cluster_id = "c-test123" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc import ( + ack_cluster_vpc, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + vpc_id='vpc-test123', + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_vpc() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == cluster_id + assert "is deployed in VPC" in result[0].status_extended + + def test_cluster_vpc_id_fail(self): + ack_client = mock.MagicMock + cluster_id = "c-test456" + cluster_arn = ( + f"acs:ack:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:cluster/{cluster_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc.ack_client", + new=ack_client, + ): + from prowler.providers.alibabacloud.services.ack.ack_cluster_vpc.ack_cluster_vpc import ( + ack_cluster_vpc, + ) + from prowler.providers.alibabacloud.services.ack.ack_service import ( + Cluster, + ) + + ack_client.clusters = { + cluster_arn: Cluster( + cluster_id=cluster_id, + cluster_name="test-cluster", + arn=cluster_arn, + region=ALIBABACLOUD_REGION, + vpc_id='', + ) + } + ack_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ack_cluster_vpc() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == cluster_id + assert "is not deployed in a VPC" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/actiontrail/__init__.py b/tests/providers/alibabacloud/services/actiontrail/__init__.py new file mode 100644 index 0000000000..a50065e516 --- /dev/null +++ b/tests/providers/alibabacloud/services/actiontrail/__init__.py @@ -0,0 +1 @@ +"""ActionTrail Service Tests""" diff --git a/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py new file mode 100644 index 0000000000..7e6391a4f8 --- /dev/null +++ b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/__init__.py @@ -0,0 +1 @@ +"""ActionTrail Check Tests""" diff --git a/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled_test.py b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled_test.py new file mode 100644 index 0000000000..13859c72c1 --- /dev/null +++ b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_enabled/actiontrail_trail_enabled_test.py @@ -0,0 +1,102 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_actiontrail_trail_enabled: + def test_no_trails(self): + actiontrail_client = mock.MagicMock + actiontrail_client.trails = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled import ( + actiontrail_trail_enabled, + ) + + actiontrail_client.account_id = ALIBABACLOUD_ACCOUNT_ID + check = actiontrail_trail_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "No enabled ActionTrail trails" in result[0].status_extended + + def test_trail_disabled(self): + actiontrail_client = mock.MagicMock + trail_arn = f"acs:actiontrail::{ALIBABACLOUD_ACCOUNT_ID}:trail/test-trail" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled import ( + actiontrail_trail_enabled, + ) + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_service import ( + Trail, + ) + + actiontrail_client.trails = { + trail_arn: Trail( + name="test-trail", + arn=trail_arn, + region="global", + status="Disabled", + ) + } + actiontrail_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = actiontrail_trail_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "No enabled ActionTrail trails" in result[0].status_extended + + def test_trail_enabled(self): + actiontrail_client = mock.MagicMock + trail_arn = f"acs:actiontrail::{ALIBABACLOUD_ACCOUNT_ID}:trail/test-trail" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_enabled.actiontrail_trail_enabled import ( + actiontrail_trail_enabled, + ) + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_service import ( + Trail, + ) + + actiontrail_client.trails = { + trail_arn: Trail( + name="test-trail", + arn=trail_arn, + region="global", + status="Enabled", + ) + } + actiontrail_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = actiontrail_trail_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert "enabled trail(s)" in result[0].status_extended + assert "test-trail" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py new file mode 100644 index 0000000000..7e6391a4f8 --- /dev/null +++ b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/__init__.py @@ -0,0 +1 @@ +"""ActionTrail Check Tests""" diff --git a/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events_test.py b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events_test.py new file mode 100644 index 0000000000..0f3fc632c6 --- /dev/null +++ b/tests/providers/alibabacloud/services/actiontrail/actiontrail_trail_logs_all_events/actiontrail_trail_logs_all_events_test.py @@ -0,0 +1,99 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_actiontrail_trail_logs_all_events: + def test_no_trails(self): + actiontrail_client = mock.MagicMock + actiontrail_client.trails = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events import ( + actiontrail_trail_logs_all_events, + ) + + check = actiontrail_trail_logs_all_events() + result = check.execute() + assert len(result) == 0 + + def test_trail_logs_only_write_events(self): + actiontrail_client = mock.MagicMock + trail_arn = f"acs:actiontrail::{ALIBABACLOUD_ACCOUNT_ID}:trail/test-trail" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events import ( + actiontrail_trail_logs_all_events, + ) + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_service import ( + Trail, + ) + + actiontrail_client.trails = { + trail_arn: Trail( + name="test-trail", + arn=trail_arn, + region="global", + event_rw="Write", + ) + } + actiontrail_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = actiontrail_trail_logs_all_events() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "test-trail" + assert "only logs Write events" in result[0].status_extended + + def test_trail_logs_all_events(self): + actiontrail_client = mock.MagicMock + trail_arn = f"acs:actiontrail::{ALIBABACLOUD_ACCOUNT_ID}:trail/test-trail" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events.actiontrail_client", + new=actiontrail_client, + ): + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_trail_logs_all_events.actiontrail_trail_logs_all_events import ( + actiontrail_trail_logs_all_events, + ) + from prowler.providers.alibabacloud.services.actiontrail.actiontrail_service import ( + Trail, + ) + + actiontrail_client.trails = { + trail_arn: Trail( + name="test-trail", + arn=trail_arn, + region="global", + event_rw="All", + ) + } + actiontrail_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = actiontrail_trail_logs_all_events() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "test-trail" + assert "logs all events" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ecs/__init__.py b/tests/providers/alibabacloud/services/ecs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled_test.py b/tests/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled_test.py new file mode 100644 index 0000000000..002349909e --- /dev/null +++ b/tests/providers/alibabacloud/services/ecs/ecs_disk_encryption_enabled/ecs_disk_encryption_enabled_test.py @@ -0,0 +1,114 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ecs_disk_encryption_enabled: + def test_no_disks(self): + ecs_client = mock.MagicMock + ecs_client.disks = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled import ( + ecs_disk_encryption_enabled, + ) + + check = ecs_disk_encryption_enabled() + result = check.execute() + assert len(result) == 0 + + def test_disk_encrypted(self): + ecs_client = mock.MagicMock + disk_id = "d-test123" + disk_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:disk/{disk_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled import ( + ecs_disk_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import Disk + + ecs_client.disks = { + disk_arn: Disk( + id=disk_id, + name="test-disk", + arn=disk_arn, + region=ALIBABACLOUD_REGION, + disk_type="data", + category="cloud_essd", + size=100, + encrypted=True, + kms_key_id="kms-key-123", + status="In_use", + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_disk_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == disk_id + assert result[0].resource_arn == disk_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "is encrypted" in result[0].status_extended + assert "kms-key-123" in result[0].status_extended + + def test_disk_not_encrypted(self): + ecs_client = mock.MagicMock + disk_id = "d-test456" + disk_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:disk/{disk_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_disk_encryption_enabled.ecs_disk_encryption_enabled import ( + ecs_disk_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import Disk + + ecs_client.disks = { + disk_arn: Disk( + id=disk_id, + name="unencrypted-disk", + arn=disk_arn, + region=ALIBABACLOUD_REGION, + disk_type="system", + category="cloud_ssd", + size=50, + encrypted=False, + status="In_use", + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_disk_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == disk_id + assert result[0].resource_arn == disk_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "is not encrypted" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip_test.py b/tests/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip_test.py new file mode 100644 index 0000000000..98a7f6e9dd --- /dev/null +++ b/tests/providers/alibabacloud/services/ecs/ecs_instance_public_ip/ecs_instance_public_ip_test.py @@ -0,0 +1,113 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ecs_instance_public_ip: + def test_no_instances(self): + ecs_client = mock.MagicMock + ecs_client.instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip import ( + ecs_instance_public_ip, + ) + + check = ecs_instance_public_ip() + result = check.execute() + assert len(result) == 0 + + def test_instance_no_public_ip(self): + ecs_client = mock.MagicMock + instance_id = "i-test123" + instance_arn = ( + f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:instance/{instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip import ( + ecs_instance_public_ip, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import ( + Instance, + ) + + ecs_client.instances = { + instance_arn: Instance( + id=instance_id, + name="private-instance", + arn=instance_arn, + region=ALIBABACLOUD_REGION, + status="Running", + public_ip=None, + private_ip="10.0.1.10", + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_instance_public_ip() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == instance_id + assert "does not have a public IP" in result[0].status_extended + + def test_instance_with_public_ip(self): + ecs_client = mock.MagicMock + instance_id = "i-test456" + instance_arn = ( + f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:instance/{instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_public_ip.ecs_instance_public_ip import ( + ecs_instance_public_ip, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import ( + Instance, + ) + + ecs_client.instances = { + instance_arn: Instance( + id=instance_id, + name="public-instance", + arn=instance_arn, + region=ALIBABACLOUD_REGION, + status="Running", + public_ip="203.0.113.1", + private_ip="10.0.1.10", + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_instance_public_ip() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == instance_id + assert "has a public IP address" in result[0].status_extended + assert "203.0.113.1" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted_test.py b/tests/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted_test.py new file mode 100644 index 0000000000..4d9b2b7a67 --- /dev/null +++ b/tests/providers/alibabacloud/services/ecs/ecs_instance_ssh_access_restricted/ecs_instance_ssh_access_restricted_test.py @@ -0,0 +1,126 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ecs_instance_ssh_access_restricted: + def test_no_security_groups(self): + ecs_client = mock.MagicMock + ecs_client.security_groups = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted import ( + ecs_instance_ssh_access_restricted, + ) + + check = ecs_instance_ssh_access_restricted() + result = check.execute() + assert len(result) == 0 + + def test_ssh_access_restricted(self): + ecs_client = mock.MagicMock + sg_id = "sg-test123" + sg_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:security-group/{sg_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted import ( + ecs_instance_ssh_access_restricted, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import ( + SecurityGroup, + ) + + ecs_client.security_groups = { + sg_arn: SecurityGroup( + id=sg_id, + name="restricted-sg", + arn=sg_arn, + region=ALIBABACLOUD_REGION, + vpc_id="vpc-test123", + description="Restricted security group", + rules=[ + { + "direction": "ingress", + "protocol": "tcp", + "port_range": "22/22", + "source": "10.0.0.0/8", + } + ], + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_instance_ssh_access_restricted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == sg_id + assert result[0].resource_arn == sg_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "does not allow unrestricted SSH access" in result[0].status_extended + + def test_ssh_access_unrestricted(self): + ecs_client = mock.MagicMock + sg_id = "sg-test456" + sg_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:security-group/{sg_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted.ecs_client", + new=ecs_client, + ): + from prowler.providers.alibabacloud.services.ecs.ecs_instance_ssh_access_restricted.ecs_instance_ssh_access_restricted import ( + ecs_instance_ssh_access_restricted, + ) + from prowler.providers.alibabacloud.services.ecs.ecs_service import ( + SecurityGroup, + ) + + ecs_client.security_groups = { + sg_arn: SecurityGroup( + id=sg_id, + name="unrestricted-sg", + arn=sg_arn, + region=ALIBABACLOUD_REGION, + vpc_id="vpc-test123", + description="Unrestricted security group", + rules=[ + { + "direction": "ingress", + "protocol": "tcp", + "port_range": "22/22", + "source": "0.0.0.0/0", + } + ], + ) + } + ecs_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ecs_instance_ssh_access_restricted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == sg_id + assert result[0].resource_arn == sg_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "allows unrestricted SSH access" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/ecs/ecs_service_test.py b/tests/providers/alibabacloud/services/ecs/ecs_service_test.py new file mode 100644 index 0000000000..4cbb4f8713 --- /dev/null +++ b/tests/providers/alibabacloud/services/ecs/ecs_service_test.py @@ -0,0 +1,105 @@ +from unittest import mock +from unittest.mock import MagicMock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ECS_Service: + def test_ecs_service(self): + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ): + from prowler.providers.alibabacloud.services.ecs.ecs_service import ( + Disk, + Instance, + SecurityGroup, + ) + + ecs_client = MagicMock() + + # Mock instances + instance_id = "i-test123" + instance_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:instance/{instance_id}" + + ecs_client.instances = { + instance_arn: Instance( + id=instance_id, + name="test-instance", + arn=instance_arn, + region=ALIBABACLOUD_REGION, + status="Running", + instance_type="ecs.t6-c1m1.large", + public_ip="192.0.2.1", + private_ip="10.0.1.10", + security_groups=["sg-test123"], + vpc_id="vpc-test123", + zone_id=f"{ALIBABACLOUD_REGION}-a", + ) + } + + # Mock disks + disk_id = "d-test456" + disk_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:disk/{disk_id}" + + ecs_client.disks = { + disk_arn: Disk( + id=disk_id, + name="test-disk", + arn=disk_arn, + region=ALIBABACLOUD_REGION, + disk_type="data", + category="cloud_essd", + size=100, + encrypted=True, + kms_key_id="kms-key-123", + status="In_use", + instance_id=instance_id, + zone_id=f"{ALIBABACLOUD_REGION}-a", + ) + } + + # Mock security groups + sg_id = "sg-test789" + sg_arn = f"acs:ecs:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:security-group/{sg_id}" + + ecs_client.security_groups = { + sg_arn: SecurityGroup( + id=sg_id, + name="test-sg", + arn=sg_arn, + region=ALIBABACLOUD_REGION, + vpc_id="vpc-test123", + description="Test security group", + rules=[ + { + "direction": "ingress", + "protocol": "tcp", + "port_range": "22/22", + "source": "10.0.0.0/8", + } + ], + ) + } + + # Assertions + assert len(ecs_client.instances) == 1 + assert ecs_client.instances[instance_arn].id == instance_id + assert ecs_client.instances[instance_arn].name == "test-instance" + assert ecs_client.instances[instance_arn].region == ALIBABACLOUD_REGION + assert ecs_client.instances[instance_arn].status == "Running" + assert ecs_client.instances[instance_arn].public_ip == "192.0.2.1" + + assert len(ecs_client.disks) == 1 + assert ecs_client.disks[disk_arn].id == disk_id + assert ecs_client.disks[disk_arn].encrypted is True + assert ecs_client.disks[disk_arn].kms_key_id == "kms-key-123" + + assert len(ecs_client.security_groups) == 1 + assert ecs_client.security_groups[sg_arn].id == sg_id + assert ecs_client.security_groups[sg_arn].vpc_id == "vpc-test123" + assert len(ecs_client.security_groups[sg_arn].rules) == 1 diff --git a/tests/providers/alibabacloud/services/oss/__init__.py b/tests/providers/alibabacloud/services/oss/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive_test.py new file mode 100644 index 0000000000..ca84f9fc89 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_cors_not_overly_permissive/oss_bucket_cors_not_overly_permissive_test.py @@ -0,0 +1,112 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_cors_not_overly_permissive: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive import ( + oss_bucket_cors_not_overly_permissive, + ) + + check = oss_bucket_cors_not_overly_permissive() + result = check.execute() + assert len(result) == 0 + + def test_bucket_cors_not_permissive(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-cors-safe" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive import ( + oss_bucket_cors_not_overly_permissive, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + cors_rules=[ + { + "AllowedOrigin": ["https://example.com"], + "AllowedMethod": ["GET"], + } + ], + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_cors_not_overly_permissive() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_cors_overly_permissive(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-cors-permissive" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_cors_not_overly_permissive.oss_bucket_cors_not_overly_permissive import ( + oss_bucket_cors_not_overly_permissive, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + cors_rules=[ + { + "AllowedOrigin": ["*"], + "AllowedMethod": ["GET", "POST", "PUT", "DELETE"], + } + ], + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_cors_not_overly_permissive() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms_test.py new file mode 100644 index 0000000000..fb940bd7d4 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_default_encryption_kms/oss_bucket_default_encryption_kms_test.py @@ -0,0 +1,104 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_default_encryption_kms: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms import ( + oss_bucket_default_encryption_kms, + ) + + check = oss_bucket_default_encryption_kms() + result = check.execute() + assert len(result) == 0 + + def test_bucket_kms_encryption(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-kms" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms import ( + oss_bucket_default_encryption_kms, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + encryption_enabled=True, + encryption_algorithm="KMS", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_default_encryption_kms() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_aes256_encryption(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-aes256" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_default_encryption_kms.oss_bucket_default_encryption_kms import ( + oss_bucket_default_encryption_kms, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + encryption_enabled=True, + encryption_algorithm="AES256", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_default_encryption_kms() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled_test.py new file mode 100644 index 0000000000..e86a90d4db --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_encryption_enabled/oss_bucket_encryption_enabled_test.py @@ -0,0 +1,104 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_encryption_enabled: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled import ( + oss_bucket_encryption_enabled, + ) + + check = oss_bucket_encryption_enabled() + result = check.execute() + assert len(result) == 0 + + def test_bucket_encryption_enabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-encrypted" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled import ( + oss_bucket_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + encryption_enabled=True, + encryption_algorithm="AES256", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_encryption_disabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-unencrypted" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_encryption_enabled.oss_bucket_encryption_enabled import ( + oss_bucket_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + encryption_enabled=False, + encryption_algorithm="", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules_test.py new file mode 100644 index 0000000000..a0c6ac11ef --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_lifecycle_rules/oss_bucket_lifecycle_rules_test.py @@ -0,0 +1,109 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_lifecycle_rules: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules import ( + oss_bucket_lifecycle_rules, + ) + + check = oss_bucket_lifecycle_rules() + result = check.execute() + assert len(result) == 0 + + def test_bucket_has_lifecycle_rules(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-lifecycle" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules import ( + oss_bucket_lifecycle_rules, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + lifecycle_rules=[ + { + "id": "rule1", + "prefix": "logs/", + "status": "Enabled", + "expiration": {"days": 90} + } + ], + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_lifecycle_rules() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_no_lifecycle_rules(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-no-lifecycle" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_lifecycle_rules.oss_bucket_lifecycle_rules import ( + oss_bucket_lifecycle_rules, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + lifecycle_rules=[], + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_lifecycle_rules() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled_test.py new file mode 100644 index 0000000000..9ec880d0b7 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_logging_enabled/oss_bucket_logging_enabled_test.py @@ -0,0 +1,104 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_logging_enabled: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled import ( + oss_bucket_logging_enabled, + ) + + check = oss_bucket_logging_enabled() + result = check.execute() + assert len(result) == 0 + + def test_bucket_logging_enabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-with-logging" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled import ( + oss_bucket_logging_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + logging_enabled=True, + access_logging_target="logging-bucket", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_logging_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_logging_disabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-no-logging" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_logging_enabled.oss_bucket_logging_enabled import ( + oss_bucket_logging_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + logging_enabled=False, + access_logging_target="", + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_logging_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked_test.py new file mode 100644 index 0000000000..d37480bbf8 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_public_access_blocked/oss_bucket_public_access_blocked_test.py @@ -0,0 +1,102 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_public_access_blocked: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked import ( + oss_bucket_public_access_blocked, + ) + + check = oss_bucket_public_access_blocked() + result = check.execute() + assert len(result) == 0 + + def test_bucket_private_access(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-private" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked import ( + oss_bucket_public_access_blocked, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + public_access=False, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_public_access_blocked() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_public_access(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-public" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_public_access_blocked.oss_bucket_public_access_blocked import ( + oss_bucket_public_access_blocked, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + public_access=True, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_public_access_blocked() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist_test.py new file mode 100644 index 0000000000..67332b25c4 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_referer_whitelist/oss_bucket_referer_whitelist_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_referer_whitelist: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist import ( + oss_bucket_referer_whitelist, + ) + + check = oss_bucket_referer_whitelist() + result = check.execute() + assert len(result) == 0 + + def test_bucket_referer_whitelist_configured(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-referer" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist import ( + oss_bucket_referer_whitelist, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + referer_config={ + "AllowEmpty": False, + "RefererList": ["https://example.com"] + }, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_referer_whitelist() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_referer_whitelist_not_configured(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-no-referer" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_referer_whitelist.oss_bucket_referer_whitelist import ( + oss_bucket_referer_whitelist, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + referer_config={ + "AllowEmpty": True, + "RefererList": [] + }, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_referer_whitelist() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration_test.py new file mode 100644 index 0000000000..702dece279 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_transfer_acceleration/oss_bucket_transfer_acceleration_test.py @@ -0,0 +1,102 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_transfer_acceleration: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration import ( + oss_bucket_transfer_acceleration, + ) + + check = oss_bucket_transfer_acceleration() + result = check.execute() + assert len(result) == 0 + + def test_bucket_transfer_acceleration_enabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-acceleration" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration import ( + oss_bucket_transfer_acceleration, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + transfer_acceleration=True, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_transfer_acceleration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_transfer_acceleration_disabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-no-acceleration" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_transfer_acceleration.oss_bucket_transfer_acceleration import ( + oss_bucket_transfer_acceleration, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + transfer_acceleration=False, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_transfer_acceleration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/__init__.py b/tests/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled_test.py b/tests/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled_test.py new file mode 100644 index 0000000000..cb07aa7773 --- /dev/null +++ b/tests/providers/alibabacloud/services/oss/oss_bucket_versioning_enabled/oss_bucket_versioning_enabled_test.py @@ -0,0 +1,102 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_oss_bucket_versioning_enabled: + def test_no_buckets(self): + oss_client = mock.MagicMock + oss_client.buckets = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled import ( + oss_bucket_versioning_enabled, + ) + + check = oss_bucket_versioning_enabled() + result = check.execute() + assert len(result) == 0 + + def test_bucket_versioning_enabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-versioned" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled import ( + oss_bucket_versioning_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + versioning_enabled=True, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_versioning_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_bucket_versioning_disabled(self): + oss_client = mock.MagicMock + bucket_name = "test-bucket-no-versioning" + bucket_arn = f"acs:oss:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:bucket/{bucket_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled.oss_client", + new=oss_client, + ): + from prowler.providers.alibabacloud.services.oss.oss_bucket_versioning_enabled.oss_bucket_versioning_enabled import ( + oss_bucket_versioning_enabled, + ) + from prowler.providers.alibabacloud.services.oss.oss_service import Bucket + + oss_client.buckets = { + bucket_arn: Bucket( + name=bucket_name, + arn=bucket_arn, + region=ALIBABACLOUD_REGION, + creation_date="2023-01-01", + versioning_enabled=False, + ) + } + oss_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = oss_bucket_versioning_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == bucket_name + assert result[0].resource_arn == bucket_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/ram/__init__.py b/tests/providers/alibabacloud/services/ram/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_access_key_rotation/__init__.py b/tests/providers/alibabacloud/services/ram/ram_access_key_rotation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation_test.py b/tests/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation_test.py new file mode 100644 index 0000000000..bd9da7ef1d --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_access_key_rotation/ram_access_key_rotation_test.py @@ -0,0 +1,110 @@ +from unittest import mock +from datetime import datetime, timedelta + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_access_key_rotation: + def test_no_users(self): + ram_client = mock.MagicMock + ram_client.users = {{}} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation import ( + ram_access_key_rotation, + ) + + check = ram_access_key_rotation() + result = check.execute() + assert len(result) == 0 + + def test_access_key_rotated_recently(self): + ram_client = mock.MagicMock + user_id = "test-user-123" + user_arn = f"acs:ram::{{ALIBABACLOUD_ACCOUNT_ID}}:user/{{user_id}}" + recent_date = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d") + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation import ( + ram_access_key_rotation, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User, AccessKey + + ram_client.users = {{ + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + access_keys=[ + AccessKey( + access_key_id="LTAI_test", + user_name="test-user", + status="Active", + create_date=recent_date, + ) + ], + ) + }} + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_access_key_rotation() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "PASS" for r in result) + + def test_access_key_not_rotated(self): + ram_client = mock.MagicMock + user_id = "test-user-456" + user_arn = f"acs:ram::{{ALIBABACLOUD_ACCOUNT_ID}}:user/{{user_id}}" + old_date = (datetime.now() - timedelta(days=120)).strftime("%Y-%m-%d") + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_access_key_rotation.ram_access_key_rotation import ( + ram_access_key_rotation, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User, AccessKey + + ram_client.users = {{ + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + access_keys=[ + AccessKey( + access_key_id="LTAI_old", + user_name="test-user", + status="Active", + create_date=old_date, + ) + ], + ) + }} + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_access_key_rotation() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "FAIL" for r in result) diff --git a/tests/providers/alibabacloud/services/ram/ram_inactive_users_disabled/__init__.py b/tests/providers/alibabacloud/services/ram/ram_inactive_users_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled_test.py b/tests/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled_test.py new file mode 100644 index 0000000000..c705d79016 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_inactive_users_disabled/ram_inactive_users_disabled_test.py @@ -0,0 +1,96 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_inactive_users_disabled: + def test_no_users(self): + ram_client = mock.MagicMock + ram_client.users = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled import ( + ram_inactive_users_disabled, + ) + + check = ram_inactive_users_disabled() + result = check.execute() + assert len(result) == 0 + + def test_ram_inactive_users_disabled_pass(self): + ram_client = mock.MagicMock + user_id = "test-user-123" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled import ( + ram_inactive_users_disabled, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + last_login_date="2024-12-01", + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_inactive_users_disabled() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "PASS" for r in result) + + def test_ram_inactive_users_disabled_fail(self): + ram_client = mock.MagicMock + user_id = "test-user-456" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_inactive_users_disabled.ram_inactive_users_disabled import ( + ram_inactive_users_disabled, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + last_login_date="2023-01-01", + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_inactive_users_disabled() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "FAIL" for r in result) diff --git a/tests/providers/alibabacloud/services/ram/ram_no_admin_privileges/__init__.py b/tests/providers/alibabacloud/services/ram/ram_no_admin_privileges/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges_test.py b/tests/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges_test.py new file mode 100644 index 0000000000..63ead6d334 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_no_admin_privileges/ram_no_admin_privileges_test.py @@ -0,0 +1,96 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_no_admin_privileges: + def test_no_users(self): + ram_client = mock.MagicMock + ram_client.users = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges import ( + ram_no_admin_privileges, + ) + + check = ram_no_admin_privileges() + result = check.execute() + assert len(result) == 0 + + def test_ram_no_admin_privileges_pass(self): + ram_client = mock.MagicMock + user_id = "test-user-123" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges import ( + ram_no_admin_privileges, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + attached_policies=[], + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_no_admin_privileges() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "PASS" for r in result) + + def test_ram_no_admin_privileges_fail(self): + ram_client = mock.MagicMock + user_id = "test-user-456" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_no_admin_privileges.ram_no_admin_privileges import ( + ram_no_admin_privileges, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + attached_policies=[{"PolicyName": "AdministratorAccess", "PolicyType": "System"}], + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_no_admin_privileges() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "FAIL" for r in result) diff --git a/tests/providers/alibabacloud/services/ram/ram_password_expiration/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_expiration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration_test.py b/tests/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration_test.py new file mode 100644 index 0000000000..12abe34c0e --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_expiration/ram_password_expiration_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_expiration: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration import ( + ram_password_expiration, + ) + + check = ram_password_expiration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration import ( + ram_password_expiration, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + max_password_age=90, + ) + + check = ram_password_expiration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "password expiration" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_expiration.ram_password_expiration import ( + ram_password_expiration, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + max_password_age=0, + ) + + check = ram_password_expiration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_minimum_length/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_minimum_length/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length_test.py b/tests/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length_test.py new file mode 100644 index 0000000000..5cf43cfa27 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_minimum_length/ram_password_minimum_length_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_minimum_length: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length import ( + ram_password_minimum_length, + ) + + check = ram_password_minimum_length() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length import ( + ram_password_minimum_length, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + minimum_length=14, + ) + + check = ram_password_minimum_length() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "14+" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_minimum_length.ram_password_minimum_length import ( + ram_password_minimum_length, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + minimum_length=8, + ) + + check = ram_password_minimum_length() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_lowercase/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_require_lowercase/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase_test.py b/tests/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase_test.py new file mode 100644 index 0000000000..f38cd09ab7 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_require_lowercase/ram_password_require_lowercase_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_require_lowercase: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase import ( + ram_password_require_lowercase, + ) + + check = ram_password_require_lowercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase import ( + ram_password_require_lowercase, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_lowercase=True, + ) + + check = ram_password_require_lowercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "lowercase" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_lowercase.ram_password_require_lowercase import ( + ram_password_require_lowercase, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_lowercase=False, + ) + + check = ram_password_require_lowercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_numbers/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_require_numbers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers_test.py b/tests/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers_test.py new file mode 100644 index 0000000000..fe94ae7032 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_require_numbers/ram_password_require_numbers_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_require_numbers: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers import ( + ram_password_require_numbers, + ) + + check = ram_password_require_numbers() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers import ( + ram_password_require_numbers, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_numbers=True, + ) + + check = ram_password_require_numbers() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "numbers" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_numbers.ram_password_require_numbers import ( + ram_password_require_numbers, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_numbers=False, + ) + + check = ram_password_require_numbers() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_symbols/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_require_symbols/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols_test.py b/tests/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols_test.py new file mode 100644 index 0000000000..3f5e3330bd --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_require_symbols/ram_password_require_symbols_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_require_symbols: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols import ( + ram_password_require_symbols, + ) + + check = ram_password_require_symbols() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols import ( + ram_password_require_symbols, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_symbols=True, + ) + + check = ram_password_require_symbols() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "symbols" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_symbols.ram_password_require_symbols import ( + ram_password_require_symbols, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_symbols=False, + ) + + check = ram_password_require_symbols() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_uppercase/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_require_uppercase/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase_test.py b/tests/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase_test.py new file mode 100644 index 0000000000..72bdbe02a4 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_require_uppercase/ram_password_require_uppercase_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_require_uppercase: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase import ( + ram_password_require_uppercase, + ) + + check = ram_password_require_uppercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase import ( + ram_password_require_uppercase, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_uppercase=True, + ) + + check = ram_password_require_uppercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "uppercase" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_require_uppercase.ram_password_require_uppercase import ( + ram_password_require_uppercase, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + require_uppercase=False, + ) + + check = ram_password_require_uppercase() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_retry_limits/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_retry_limits/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits_test.py b/tests/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits_test.py new file mode 100644 index 0000000000..65128b88f7 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_retry_limits/ram_password_retry_limits_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_retry_limits: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits import ( + ram_password_retry_limits, + ) + + check = ram_password_retry_limits() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits import ( + ram_password_retry_limits, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + max_login_attempts=5, + ) + + check = ram_password_retry_limits() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "login attempt limits" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_retry_limits.ram_password_retry_limits import ( + ram_password_retry_limits, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + max_login_attempts=10, + ) + + check = ram_password_retry_limits() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_password_reuse_prevention/__init__.py b/tests/providers/alibabacloud/services/ram/ram_password_reuse_prevention/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention_test.py b/tests/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention_test.py new file mode 100644 index 0000000000..0f18f5c79d --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_password_reuse_prevention/ram_password_reuse_prevention_test.py @@ -0,0 +1,88 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_password_reuse_prevention: + def test_no_password_policy(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.password_policy = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention import ( + ram_password_reuse_prevention, + ) + + check = ram_password_reuse_prevention() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + + def test_password_policy_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention import ( + ram_password_reuse_prevention, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + password_reuse_prevention=5, + ) + + check = ram_password_reuse_prevention() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "password-policy" + assert "password reuse prevention" in result[0].status_extended.lower() + + def test_password_policy_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_password_reuse_prevention.ram_password_reuse_prevention import ( + ram_password_reuse_prevention, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import PasswordPolicy + + ram_client.password_policy = PasswordPolicy( + password_reuse_prevention=0, + ) + + check = ram_password_reuse_prevention() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "password-policy" diff --git a/tests/providers/alibabacloud/services/ram/ram_root_access_keys_absent/__init__.py b/tests/providers/alibabacloud/services/ram/ram_root_access_keys_absent/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent_test.py b/tests/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent_test.py new file mode 100644 index 0000000000..17fcc02348 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_root_access_keys_absent/ram_root_access_keys_absent_test.py @@ -0,0 +1,57 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_root_access_keys_absent: + def test_ram_root_access_keys_absent_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_has_access_keys = False + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_access_keys_absent.ram_root_access_keys_absent.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_access_keys_absent.ram_root_access_keys_absent import ( + ram_root_access_keys_absent, + ) + + check = ram_root_access_keys_absent() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "root-account" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "access keys" in result[0].status_extended.lower() + + def test_ram_root_access_keys_absent_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_has_access_keys = True + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_access_keys_absent.ram_root_access_keys_absent.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_access_keys_absent.ram_root_access_keys_absent import ( + ram_root_access_keys_absent, + ) + + check = ram_root_access_keys_absent() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "root-account" diff --git a/tests/providers/alibabacloud/services/ram/ram_root_mfa_enabled/__init__.py b/tests/providers/alibabacloud/services/ram/ram_root_mfa_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled_test.py b/tests/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled_test.py new file mode 100644 index 0000000000..1e65e998f4 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_root_mfa_enabled/ram_root_mfa_enabled_test.py @@ -0,0 +1,57 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_root_mfa_enabled: + def test_ram_root_mfa_enabled_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_mfa_enabled = True + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_mfa_enabled.ram_root_mfa_enabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_mfa_enabled.ram_root_mfa_enabled import ( + ram_root_mfa_enabled, + ) + + check = ram_root_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "root-account" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "MFA" in result[0].status_extended.lower() + + def test_ram_root_mfa_enabled_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_mfa_enabled = False + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_mfa_enabled.ram_root_mfa_enabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_mfa_enabled.ram_root_mfa_enabled import ( + ram_root_mfa_enabled, + ) + + check = ram_root_mfa_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "root-account" diff --git a/tests/providers/alibabacloud/services/ram/ram_root_usage_minimized/__init__.py b/tests/providers/alibabacloud/services/ram/ram_root_usage_minimized/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized_test.py b/tests/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized_test.py new file mode 100644 index 0000000000..a6f8cca97b --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_root_usage_minimized/ram_root_usage_minimized_test.py @@ -0,0 +1,57 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_root_usage_minimized: + def test_ram_root_usage_minimized_pass(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_last_activity = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_usage_minimized.ram_root_usage_minimized.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_usage_minimized.ram_root_usage_minimized import ( + ram_root_usage_minimized, + ) + + check = ram_root_usage_minimized() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "root-account" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "usage" in result[0].status_extended.lower() + + def test_ram_root_usage_minimized_fail(self): + ram_client = mock.MagicMock + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + ram_client.root_last_activity = "2024-01-01" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_root_usage_minimized.ram_root_usage_minimized.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_root_usage_minimized.ram_root_usage_minimized import ( + ram_root_usage_minimized, + ) + + check = ram_root_usage_minimized() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "root-account" diff --git a/tests/providers/alibabacloud/services/ram/ram_service_test.py b/tests/providers/alibabacloud/services/ram/ram_service_test.py new file mode 100644 index 0000000000..dca0416922 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_service_test.py @@ -0,0 +1,90 @@ +from unittest.mock import patch +from prowler.providers.alibabacloud.services.ram.ram_service import ( + RAM, + User, + PasswordPolicy, + AccessKey, +) +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_RAM_Service: + def test_service(self): + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ): + ram = RAM(set_mocked_alibabacloud_provider()) + + assert ram.service == "ram" + assert ram.account_id == ALIBABACLOUD_ACCOUNT_ID + assert ram.region == ALIBABACLOUD_REGION + assert len(ram.regions) > 0 + + def test_user_creation(self): + user_id = "test-user-123" + arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + user = User( + id=user_id, + name="test-user", + arn=arn, + console_login_enabled=True, + mfa_enabled=True, + access_keys=[ + AccessKey( + access_key_id="LTAI_test123", + user_name="test-user", + status="Active", + create_date="2024-01-01", + ) + ], + ) + + assert user.id == user_id + assert user.name == "test-user" + assert user.arn == arn + assert user.console_login_enabled is True + assert user.mfa_enabled is True + assert len(user.access_keys) == 1 + assert user.access_keys[0].access_key_id == "LTAI_test123" + + def test_password_policy_creation(self): + policy = PasswordPolicy( + minimum_length=14, + require_lowercase=True, + require_uppercase=True, + require_numbers=True, + require_symbols=True, + max_login_attempts=5, + max_password_age=90, + password_reuse_prevention=5, + ) + + assert policy.minimum_length == 14 + assert policy.require_lowercase is True + assert policy.require_uppercase is True + assert policy.require_numbers is True + assert policy.require_symbols is True + assert policy.max_login_attempts == 5 + assert policy.max_password_age == 90 + assert policy.password_reuse_prevention == 5 + + def test_access_key_creation(self): + access_key = AccessKey( + access_key_id="LTAI_test", + user_name="test-user", + status="Active", + create_date="2024-01-01", + last_used_date="2024-12-01", + ) + + assert access_key.access_key_id == "LTAI_test" + assert access_key.user_name == "test-user" + assert access_key.status == "Active" + assert access_key.create_date == "2024-01-01" + assert access_key.last_used_date == "2024-12-01" diff --git a/tests/providers/alibabacloud/services/ram/ram_user_mfa_enabled/__init__.py b/tests/providers/alibabacloud/services/ram/ram_user_mfa_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled_test.py b/tests/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled_test.py new file mode 100644 index 0000000000..ead9b7af2c --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_user_mfa_enabled/ram_user_mfa_enabled_test.py @@ -0,0 +1,96 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_user_mfa_enabled: + def test_no_users(self): + ram_client = mock.MagicMock + ram_client.users = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled import ( + ram_user_mfa_enabled, + ) + + check = ram_user_mfa_enabled() + result = check.execute() + assert len(result) == 0 + + def test_ram_user_mfa_enabled_pass(self): + ram_client = mock.MagicMock + user_id = "test-user-123" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled import ( + ram_user_mfa_enabled, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + mfa_enabled=True, + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_user_mfa_enabled() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "PASS" for r in result) + + def test_ram_user_mfa_enabled_fail(self): + ram_client = mock.MagicMock + user_id = "test-user-456" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_mfa_enabled.ram_user_mfa_enabled import ( + ram_user_mfa_enabled, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + mfa_enabled=False, + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_user_mfa_enabled() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "FAIL" for r in result) diff --git a/tests/providers/alibabacloud/services/ram/ram_user_policy_via_groups/__init__.py b/tests/providers/alibabacloud/services/ram/ram_user_policy_via_groups/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups_test.py b/tests/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups_test.py new file mode 100644 index 0000000000..d1bca44392 --- /dev/null +++ b/tests/providers/alibabacloud/services/ram/ram_user_policy_via_groups/ram_user_policy_via_groups_test.py @@ -0,0 +1,96 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_ram_user_policy_via_groups: + def test_no_users(self): + ram_client = mock.MagicMock + ram_client.users = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups import ( + ram_user_policy_via_groups, + ) + + check = ram_user_policy_via_groups() + result = check.execute() + assert len(result) == 0 + + def test_ram_user_policy_via_groups_pass(self): + ram_client = mock.MagicMock + user_id = "test-user-123" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups import ( + ram_user_policy_via_groups, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + attached_policies=[], + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_user_policy_via_groups() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "PASS" for r in result) + + def test_ram_user_policy_via_groups_fail(self): + ram_client = mock.MagicMock + user_id = "test-user-456" + user_arn = f"acs:ram::{ALIBABACLOUD_ACCOUNT_ID}:user/{user_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups.ram_client", + new=ram_client, + ): + from prowler.providers.alibabacloud.services.ram.ram_user_policy_via_groups.ram_user_policy_via_groups import ( + ram_user_policy_via_groups, + ) + from prowler.providers.alibabacloud.services.ram.ram_service import User + + ram_client.users = { + user_arn: User( + id=user_id, + name="test-user", + arn=user_arn, + console_login_enabled=True, + attached_policies=[{"PolicyName": "AdministratorAccess", "PolicyType": "System"}], + ) + } + ram_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = ram_user_policy_via_groups() + result = check.execute() + + assert len(result) >= 1 + assert any(r.status == "FAIL" for r in result) diff --git a/tests/providers/alibabacloud/services/rds/__init__.py b/tests/providers/alibabacloud/services/rds/__init__.py new file mode 100644 index 0000000000..6463e915d8 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/__init__.py @@ -0,0 +1 @@ +"""RDS Service Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log_test.py new file mode 100644 index 0000000000..0171267a8d --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_audit_log/rds_instance_audit_log_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_audit_log: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log import ( + rds_instance_audit_log, + ) + + check = rds_instance_audit_log() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_audit_log_enabled_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log import ( + rds_instance_audit_log, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + audit_log_enabled=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_audit_log() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has SQL audit logging enabled" in result[0].status_extended + + def test_db_instance_audit_log_enabled_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_audit_log.rds_instance_audit_log import ( + rds_instance_audit_log, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + audit_log_enabled=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_audit_log() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have SQL audit logging enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade_test.py new file mode 100644 index 0000000000..4ecd64e1fe --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_auto_minor_version_upgrade/rds_instance_auto_minor_version_upgrade_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_auto_minor_version_upgrade: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade import ( + rds_instance_auto_minor_version_upgrade, + ) + + check = rds_instance_auto_minor_version_upgrade() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_auto_minor_version_upgrade_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade import ( + rds_instance_auto_minor_version_upgrade, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + auto_minor_version_upgrade=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_auto_minor_version_upgrade() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has automatic minor version upgrades enabled" in result[0].status_extended + + def test_db_instance_auto_minor_version_upgrade_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_auto_minor_version_upgrade.rds_instance_auto_minor_version_upgrade import ( + rds_instance_auto_minor_version_upgrade, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + auto_minor_version_upgrade=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_auto_minor_version_upgrade() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have automatic minor version upgrades enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled_test.py new file mode 100644 index 0000000000..4d270230d7 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_backup_enabled/rds_instance_backup_enabled_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_backup_enabled: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled import ( + rds_instance_backup_enabled, + ) + + check = rds_instance_backup_enabled() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_backup_enabled_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled import ( + rds_instance_backup_enabled, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + backup_enabled=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_backup_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has automated backups enabled" in result[0].status_extended + + def test_db_instance_backup_enabled_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled import ( + rds_instance_backup_enabled, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + backup_enabled=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_backup_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have automated backups enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection_test.py new file mode 100644 index 0000000000..26e337146a --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_deletion_protection/rds_instance_deletion_protection_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_deletion_protection: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection import ( + rds_instance_deletion_protection, + ) + + check = rds_instance_deletion_protection() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_deletion_protection_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection import ( + rds_instance_deletion_protection, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + deletion_protection=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_deletion_protection() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has deletion protection enabled" in result[0].status_extended + + def test_db_instance_deletion_protection_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_deletion_protection.rds_instance_deletion_protection import ( + rds_instance_deletion_protection, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + deletion_protection=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_deletion_protection() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have deletion protection enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_encryption/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption_test.py new file mode 100644 index 0000000000..59f1f416d6 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_encryption/rds_instance_encryption_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_encryption: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption import ( + rds_instance_encryption, + ) + + check = rds_instance_encryption() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_encryption_enabled_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption import ( + rds_instance_encryption, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + encryption_enabled=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_encryption() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has Transparent Data Encryption (TDE) enabled" in result[0].status_extended + + def test_db_instance_encryption_enabled_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_encryption.rds_instance_encryption import ( + rds_instance_encryption, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + encryption_enabled=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_encryption() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have Transparent Data Encryption (TDE) enabled" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc_test.py new file mode 100644 index 0000000000..31f6b4bdb9 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_in_vpc/rds_instance_in_vpc_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_in_vpc: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc import ( + rds_instance_in_vpc, + ) + + check = rds_instance_in_vpc() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_vpc_id_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc import ( + rds_instance_in_vpc, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + vpc_id='vpc-test123', + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_in_vpc() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "is deployed in VPC" in result[0].status_extended + + def test_db_instance_vpc_id_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_in_vpc.rds_instance_in_vpc import ( + rds_instance_in_vpc, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + vpc_id='', + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_in_vpc() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "is not deployed in a VPC" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py new file mode 100644 index 0000000000..c925ad69bd --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_multi_az: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az import ( + rds_instance_multi_az, + ) + + check = rds_instance_multi_az() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_multi_az_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az import ( + rds_instance_multi_az, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + multi_az=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_multi_az() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "is deployed across multiple availability zones" in result[0].status_extended + + def test_db_instance_multi_az_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_multi_az.rds_instance_multi_az import ( + rds_instance_multi_az, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + multi_az=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_multi_az() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "is not deployed across multiple availability zones" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_public_access/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access_test.py new file mode 100644 index 0000000000..160a982df9 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_public_access/rds_instance_public_access_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_public_access: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access import ( + rds_instance_public_access, + ) + + check = rds_instance_public_access() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_public_access_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access import ( + rds_instance_public_access, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + public_access=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_public_access() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "does not allow public access" in result[0].status_extended + + def test_db_instance_public_access_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_public_access.rds_instance_public_access import ( + rds_instance_public_access, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + public_access=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_public_access() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "allows public access" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py b/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py new file mode 100644 index 0000000000..37482f5908 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/__init__.py @@ -0,0 +1 @@ +"""RDS Check Tests""" diff --git a/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled_test.py b/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled_test.py new file mode 100644 index 0000000000..b18acd6552 --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_instance_ssl_enabled/rds_instance_ssl_enabled_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_rds_instance_ssl_enabled: + def test_no_db_instances(self): + rds_client = mock.MagicMock + rds_client.db_instances = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled import ( + rds_instance_ssl_enabled, + ) + + check = rds_instance_ssl_enabled() + result = check.execute() + assert len(result) == 0 + + def test_db_instance_ssl_enabled_pass(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test123" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled import ( + rds_instance_ssl_enabled, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + ssl_enabled=True, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_ssl_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == db_instance_id + assert "has SSL enabled for encrypted connections" in result[0].status_extended + + def test_db_instance_ssl_enabled_fail(self): + rds_client = mock.MagicMock + db_instance_id = "rm-test456" + db_instance_arn = ( + f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled.rds_client", + new=rds_client, + ): + from prowler.providers.alibabacloud.services.rds.rds_instance_ssl_enabled.rds_instance_ssl_enabled import ( + rds_instance_ssl_enabled, + ) + from prowler.providers.alibabacloud.services.rds.rds_service import ( + DBInstance, + ) + + rds_client.db_instances = { + db_instance_arn: DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=db_instance_arn, + region=ALIBABACLOUD_REGION, + ssl_enabled=False, + ) + } + rds_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = rds_instance_ssl_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == db_instance_id + assert "does not have SSL enabled. Enable SSL to encrypt data in transit" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/rds/rds_service_test.py b/tests/providers/alibabacloud/services/rds/rds_service_test.py new file mode 100644 index 0000000000..f14369da3e --- /dev/null +++ b/tests/providers/alibabacloud/services/rds/rds_service_test.py @@ -0,0 +1,71 @@ +from unittest.mock import patch +from prowler.providers.alibabacloud.services.rds.rds_service import RDS, DBInstance +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_RDS_Service: + def test_service(self): + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ): + rds = RDS(set_mocked_alibabacloud_provider()) + + assert rds.service == "rds" + assert rds.account_id == ALIBABACLOUD_ACCOUNT_ID + assert rds.region == ALIBABACLOUD_REGION + assert len(rds.regions) > 0 + + def test_db_instance_creation(self): + db_instance_id = "rm-test123" + arn = f"acs:rds:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:dbinstance/{db_instance_id}" + + db_instance = DBInstance( + db_instance_id=db_instance_id, + db_instance_name="test-db", + arn=arn, + region=ALIBABACLOUD_REGION, + engine="MySQL", + engine_version="8.0", + public_access=False, + encryption_enabled=True, + backup_retention_period=14, + ssl_enabled=True, + multi_az=True, + auto_minor_version_upgrade=True, + deletion_protection=True, + audit_log_enabled=True, + vpc_id="vpc-test123", + security_ips=["192.168.0.0/16"], + ) + + assert db_instance.db_instance_id == db_instance_id + assert db_instance.db_instance_name == "test-db" + assert db_instance.arn == arn + assert db_instance.region == ALIBABACLOUD_REGION + assert db_instance.engine == "MySQL" + assert db_instance.engine_version == "8.0" + assert db_instance.public_access is False + assert db_instance.encryption_enabled is True + assert db_instance.backup_retention_period == 14 + assert db_instance.ssl_enabled is True + assert db_instance.multi_az is True + assert db_instance.auto_minor_version_upgrade is True + assert db_instance.deletion_protection is True + assert db_instance.audit_log_enabled is True + assert db_instance.vpc_id == "vpc-test123" + assert db_instance.security_ips == ["192.168.0.0/16"] + + def test_db_instance_default_security_ips(self): + db_instance = DBInstance( + db_instance_id="rm-test", + db_instance_name="test-db", + arn="arn", + region=ALIBABACLOUD_REGION, + ) + + assert db_instance.security_ips == ["0.0.0.0/0"] diff --git a/tests/providers/alibabacloud/services/securitycenter/__init__.py b/tests/providers/alibabacloud/services/securitycenter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/__init__.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware_test.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware_test.py new file mode 100644 index 0000000000..98040a7365 --- /dev/null +++ b/tests/providers/alibabacloud/services/securitycenter/securitycenter_anti_ransomware/securitycenter_anti_ransomware_test.py @@ -0,0 +1,90 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_securitycenter_anti_ransomware: + def test_no_config(self): + securitycenter_client = mock.MagicMock + securitycenter_client.config = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware import ( + securitycenter_anti_ransomware, + ) + + check = securitycenter_anti_ransomware() + result = check.execute() + assert len(result) == 0 + + def test_anti_ransomware_enabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware import ( + securitycenter_anti_ransomware, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + anti_ransomware=True, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_anti_ransomware() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].region == ALIBABACLOUD_REGION + + def test_anti_ransomware_disabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_anti_ransomware.securitycenter_anti_ransomware import ( + securitycenter_anti_ransomware, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + anti_ransomware=False, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_anti_ransomware() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_enabled/__init__.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled_test.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled_test.py new file mode 100644 index 0000000000..caf3e60e18 --- /dev/null +++ b/tests/providers/alibabacloud/services/securitycenter/securitycenter_enabled/securitycenter_enabled_test.py @@ -0,0 +1,90 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_securitycenter_enabled: + def test_no_config(self): + securitycenter_client = mock.MagicMock + securitycenter_client.config = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled import ( + securitycenter_enabled, + ) + + check = securitycenter_enabled() + result = check.execute() + assert len(result) == 0 + + def test_securitycenter_enabled_pass(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled import ( + securitycenter_enabled, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + version="Advanced", + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].region == ALIBABACLOUD_REGION + + def test_securitycenter_enabled_fail(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_enabled.securitycenter_enabled import ( + securitycenter_enabled, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=False, + version="Basic", + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/__init__.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection_test.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection_test.py new file mode 100644 index 0000000000..0708e0d376 --- /dev/null +++ b/tests/providers/alibabacloud/services/securitycenter/securitycenter_threat_detection/securitycenter_threat_detection_test.py @@ -0,0 +1,90 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_securitycenter_threat_detection: + def test_no_config(self): + securitycenter_client = mock.MagicMock + securitycenter_client.config = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection import ( + securitycenter_threat_detection, + ) + + check = securitycenter_threat_detection() + result = check.execute() + assert len(result) == 0 + + def test_threat_detection_enabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection import ( + securitycenter_threat_detection, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + threat_detection=True, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_threat_detection() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].region == ALIBABACLOUD_REGION + + def test_threat_detection_disabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_threat_detection.securitycenter_threat_detection import ( + securitycenter_threat_detection, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + threat_detection=False, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_threat_detection() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/__init__.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan_test.py b/tests/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan_test.py new file mode 100644 index 0000000000..7f184b9c91 --- /dev/null +++ b/tests/providers/alibabacloud/services/securitycenter/securitycenter_vulnerability_scan/securitycenter_vulnerability_scan_test.py @@ -0,0 +1,90 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_securitycenter_vulnerability_scan: + def test_no_config(self): + securitycenter_client = mock.MagicMock + securitycenter_client.config = None + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan import ( + securitycenter_vulnerability_scan, + ) + + check = securitycenter_vulnerability_scan() + result = check.execute() + assert len(result) == 0 + + def test_vulnerability_scan_enabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan import ( + securitycenter_vulnerability_scan, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + vulnerability_scan=True, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_vulnerability_scan() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].region == ALIBABACLOUD_REGION + + def test_vulnerability_scan_disabled(self): + securitycenter_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan.securitycenter_client", + new=securitycenter_client, + ): + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_vulnerability_scan.securitycenter_vulnerability_scan import ( + securitycenter_vulnerability_scan, + ) + from prowler.providers.alibabacloud.services.securitycenter.securitycenter_service import ( + SecurityCenterConfig, + ) + + securitycenter_client.config = SecurityCenterConfig( + enabled=True, + vulnerability_scan=False, + ) + securitycenter_client.account_id = ALIBABACLOUD_ACCOUNT_ID + securitycenter_client.region = ALIBABACLOUD_REGION + + check = securitycenter_vulnerability_scan() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/sls/__init__.py b/tests/providers/alibabacloud/services/sls/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_account_login_failures_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_account_login_failures_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_account_login_failures_alert/sls_account_login_failures_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_account_login_failures_alert/sls_account_login_failures_alert_test.py new file mode 100644 index 0000000000..62a0b1f4c7 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_account_login_failures_alert/sls_account_login_failures_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_account_login_failures_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures import ( + sls_alert_account_login_failures, + ) + + check = sls_alert_account_login_failures() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-login-failure-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures import ( + sls_alert_account_login_failures, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Account Login Failures", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_account_login_failures() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Account Login Failures" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-login-failure-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_account_login_failures.sls_alert_account_login_failures import ( + sls_alert_account_login_failures, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Account Login Failures", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_account_login_failures() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_ack_cluster_integration/__init__.py b/tests/providers/alibabacloud/services/sls/sls_ack_cluster_integration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_ack_cluster_integration/sls_ack_cluster_integration_test.py b/tests/providers/alibabacloud/services/sls/sls_ack_cluster_integration/sls_ack_cluster_integration_test.py new file mode 100644 index 0000000000..0e325d7f78 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_ack_cluster_integration/sls_ack_cluster_integration_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_ack_cluster_integration: + def test_sls_ack_cluster_integration_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_ack_cluster_integration.sls_ack_cluster_integration.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_ack_cluster_integration.sls_ack_cluster_integration import ( + sls_ack_cluster_integration, + ) + + check = sls_ack_cluster_integration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "SLS integration check" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_anti_ddos_log_analysis/__init__.py b/tests/providers/alibabacloud/services/sls/sls_anti_ddos_log_analysis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_anti_ddos_log_analysis/sls_anti_ddos_log_analysis_test.py b/tests/providers/alibabacloud/services/sls/sls_anti_ddos_log_analysis/sls_anti_ddos_log_analysis_test.py new file mode 100644 index 0000000000..8b68bcd2be --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_anti_ddos_log_analysis/sls_anti_ddos_log_analysis_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_anti_ddos_log_analysis: + def test_sls_anti_ddos_log_analysis_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_anti_ddos_log_analysis.sls_anti_ddos_log_analysis.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_anti_ddos_log_analysis.sls_anti_ddos_log_analysis import ( + sls_anti_ddos_log_analysis, + ) + + check = sls_anti_ddos_log_analysis() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "Anti-DDoS Log Analysis" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_log_analysis/__init__.py b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_log_analysis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_log_analysis/sls_cloud_firewall_log_analysis_test.py b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_log_analysis/sls_cloud_firewall_log_analysis_test.py new file mode 100644 index 0000000000..2dcc3cdb5b --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_log_analysis/sls_cloud_firewall_log_analysis_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_cloud_firewall_log_analysis: + def test_sls_cloud_firewall_log_analysis_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_cloud_firewall_log_analysis.sls_cloud_firewall_log_analysis.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_cloud_firewall_log_analysis.sls_cloud_firewall_log_analysis import ( + sls_cloud_firewall_log_analysis, + ) + + check = sls_cloud_firewall_log_analysis() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "Cloud Firewall Log Analysis" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_policy_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_policy_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_policy_changes_alert/sls_cloud_firewall_policy_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_policy_changes_alert/sls_cloud_firewall_policy_changes_alert_test.py new file mode 100644 index 0000000000..8df9c0d677 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_cloud_firewall_policy_changes_alert/sls_cloud_firewall_policy_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_cloud_firewall_policy_changes: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes import ( + sls_alert_cloud_firewall_policy_changes, + ) + + check = sls_alert_cloud_firewall_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-firewall-policy-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes import ( + sls_alert_cloud_firewall_policy_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Cloud Firewall Policy Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_cloud_firewall_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Cloud Firewall Policy Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-firewall-policy-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_cloud_firewall_policy_changes.sls_alert_cloud_firewall_policy_changes import ( + sls_alert_cloud_firewall_policy_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Cloud Firewall Policy Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_cloud_firewall_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_flow_log_configuration/__init__.py b/tests/providers/alibabacloud/services/sls/sls_flow_log_configuration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_flow_log_configuration/sls_flow_log_configuration_test.py b/tests/providers/alibabacloud/services/sls/sls_flow_log_configuration/sls_flow_log_configuration_test.py new file mode 100644 index 0000000000..cf871056aa --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_flow_log_configuration/sls_flow_log_configuration_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_flow_log_configuration: + def test_sls_flow_log_configuration_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_flow_log_configuration.sls_flow_log_configuration.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_flow_log_configuration.sls_flow_log_configuration import ( + sls_flow_log_configuration, + ) + + check = sls_flow_log_configuration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "Flow Log Configuration" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_kms_key_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_kms_key_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_kms_key_changes_alert/sls_kms_key_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_kms_key_changes_alert/sls_kms_key_changes_alert_test.py new file mode 100644 index 0000000000..16172b606c --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_kms_key_changes_alert/sls_kms_key_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_kms_key_changes: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes import ( + sls_alert_kms_key_changes, + ) + + check = sls_alert_kms_key_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-kms-key-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes import ( + sls_alert_kms_key_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for KMS Key Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_kms_key_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "KMS Key Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-kms-key-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_kms_key_changes.sls_alert_kms_key_changes import ( + sls_alert_kms_key_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for KMS Key Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_kms_key_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/__init__.py b/tests/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled_test.py b/tests/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled_test.py new file mode 100644 index 0000000000..7d143f476c --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_logstore_encryption_enabled/sls_logstore_encryption_enabled_test.py @@ -0,0 +1,108 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_logstore_encryption_enabled: + def test_no_logstores(self): + sls_client = mock.MagicMock + sls_client.logstores = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled import ( + sls_logstore_encryption_enabled, + ) + + check = sls_logstore_encryption_enabled() + result = check.execute() + assert len(result) == 0 + + def test_logstore_encryption_enabled_pass(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled import ( + sls_logstore_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + encrypt_conf={"enable": True, "encrypt_type": "default"}, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "has encryption enabled" in result[0].status_extended + assert "default" in result[0].status_extended + + def test_logstore_encryption_disabled_fail(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_encryption_enabled.sls_logstore_encryption_enabled import ( + sls_logstore_encryption_enabled, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + encrypt_conf={"enable": False, "encrypt_type": "default"}, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_encryption_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "does not have encryption enabled" in result[0].status_extended + assert "Enable encryption" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_retention_period/__init__.py b/tests/providers/alibabacloud/services/sls/sls_logstore_retention_period/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period_test.py b/tests/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period_test.py new file mode 100644 index 0000000000..9f7e8556d0 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_logstore_retention_period/sls_logstore_retention_period_test.py @@ -0,0 +1,148 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_logstore_retention_period: + def test_no_logstores(self): + sls_client = mock.MagicMock + sls_client.logstores = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period import ( + sls_logstore_retention_period, + ) + + check = sls_logstore_retention_period() + result = check.execute() + assert len(result) == 0 + + def test_logstore_retention_period_pass(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period import ( + sls_logstore_retention_period, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + ttl=365, + shard_count=2, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_retention_period() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "365 days" in result[0].status_extended + assert "meets 365+ day requirement" in result[0].status_extended + + def test_logstore_retention_period_fail(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period import ( + sls_logstore_retention_period, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + ttl=30, + shard_count=2, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_retention_period() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "only 30 days" in result[0].status_extended + assert "Increase to at least 365 days" in result[0].status_extended + + def test_logstore_retention_period_greater_than_365(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_retention_period.sls_logstore_retention_period import ( + sls_logstore_retention_period, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + ttl=730, # 2 years + shard_count=2, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_retention_period() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == logstore_name + assert "730 days" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/__init__.py b/tests/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled_test.py b/tests/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled_test.py new file mode 100644 index 0000000000..d699b26ece --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_logstore_web_tracking_disabled/sls_logstore_web_tracking_disabled_test.py @@ -0,0 +1,107 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_logstore_web_tracking_disabled: + def test_no_logstores(self): + sls_client = mock.MagicMock + sls_client.logstores = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled import ( + sls_logstore_web_tracking_disabled, + ) + + check = sls_logstore_web_tracking_disabled() + result = check.execute() + assert len(result) == 0 + + def test_logstore_web_tracking_disabled_pass(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled import ( + sls_logstore_web_tracking_disabled, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + enable_tracking=False, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_web_tracking_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "has web tracking disabled" in result[0].status_extended + + def test_logstore_web_tracking_enabled_fail(self): + sls_client = mock.MagicMock + project_name = "test-project" + logstore_name = "test-logstore" + logstore_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_logstore_web_tracking_disabled.sls_logstore_web_tracking_disabled import ( + sls_logstore_web_tracking_disabled, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Logstore + + sls_client.logstores = { + logstore_arn: Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=logstore_arn, + region=ALIBABACLOUD_REGION, + enable_tracking=True, + ) + } + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = sls_logstore_web_tracking_disabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == logstore_name + assert result[0].resource_arn == logstore_arn + assert result[0].region == ALIBABACLOUD_REGION + assert "has web tracking enabled" in result[0].status_extended + assert "Disable web tracking" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_multi_cloud_audit_logs/__init__.py b/tests/providers/alibabacloud/services/sls/sls_multi_cloud_audit_logs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_multi_cloud_audit_logs/sls_multi_cloud_audit_logs_test.py b/tests/providers/alibabacloud/services/sls/sls_multi_cloud_audit_logs/sls_multi_cloud_audit_logs_test.py new file mode 100644 index 0000000000..288f53f5fd --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_multi_cloud_audit_logs/sls_multi_cloud_audit_logs_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_multi_cloud_audit_logs: + def test_sls_multi_cloud_audit_logs_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_multi_cloud_audit_logs.sls_multi_cloud_audit_logs.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_multi_cloud_audit_logs.sls_multi_cloud_audit_logs import ( + sls_multi_cloud_audit_logs, + ) + + check = sls_multi_cloud_audit_logs() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "Multi-Cloud Audit Logs" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_oss_bucket_authority_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_authority_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_oss_bucket_authority_changes_alert/sls_oss_bucket_authority_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_authority_changes_alert/sls_oss_bucket_authority_changes_alert_test.py new file mode 100644 index 0000000000..d0d679b392 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_authority_changes_alert/sls_oss_bucket_authority_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_oss_bucket_authority_changes: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes import ( + sls_alert_oss_bucket_authority_changes, + ) + + check = sls_alert_oss_bucket_authority_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-oss-authority-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes import ( + sls_alert_oss_bucket_authority_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for OSS Bucket Authority Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_oss_bucket_authority_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "OSS Bucket Authority Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-oss-authority-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_authority_changes.sls_alert_oss_bucket_authority_changes import ( + sls_alert_oss_bucket_authority_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for OSS Bucket Authority Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_oss_bucket_authority_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_oss_bucket_permission_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_permission_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_oss_bucket_permission_changes_alert/sls_oss_bucket_permission_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_permission_changes_alert/sls_oss_bucket_permission_changes_alert_test.py new file mode 100644 index 0000000000..db235a052e --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_oss_bucket_permission_changes_alert/sls_oss_bucket_permission_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_oss_bucket_permission_changes: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes import ( + sls_alert_oss_bucket_permission_changes, + ) + + check = sls_alert_oss_bucket_permission_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-oss-permission-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes import ( + sls_alert_oss_bucket_permission_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for OSS Bucket Permission Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_oss_bucket_permission_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "OSS Bucket Permission Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-oss-permission-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_oss_bucket_permission_changes.sls_alert_oss_bucket_permission_changes import ( + sls_alert_oss_bucket_permission_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for OSS Bucket Permission Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_oss_bucket_permission_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_ram_policy_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_ram_policy_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_ram_policy_changes_alert/sls_ram_policy_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_ram_policy_changes_alert/sls_ram_policy_changes_alert_test.py new file mode 100644 index 0000000000..4355bb5407 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_ram_policy_changes_alert/sls_ram_policy_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_ram_policy_changes_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes import ( + sls_alert_ram_policy_changes, + ) + + check = sls_alert_ram_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-ram-policy-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes import ( + sls_alert_ram_policy_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for RAM Policy Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_ram_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "RAM Policy Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-ram-policy-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_ram_policy_changes.sls_alert_ram_policy_changes import ( + sls_alert_ram_policy_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for RAM Policy Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_ram_policy_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_rds_config_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_rds_config_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_rds_config_changes_alert/sls_rds_config_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_rds_config_changes_alert/sls_rds_config_changes_alert_test.py new file mode 100644 index 0000000000..d2ef50724c --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_rds_config_changes_alert/sls_rds_config_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_rds_config_changes: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes import ( + sls_alert_rds_config_changes, + ) + + check = sls_alert_rds_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-rds-config-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes import ( + sls_alert_rds_config_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for RDS Configuration Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_rds_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "RDS Configuration Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-rds-config-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_rds_config_changes.sls_alert_rds_config_changes import ( + sls_alert_rds_config_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for RDS Configuration Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_rds_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_root_account_logins_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_root_account_logins_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_root_account_logins_alert/sls_root_account_logins_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_root_account_logins_alert/sls_root_account_logins_alert_test.py new file mode 100644 index 0000000000..c080ae9503 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_root_account_logins_alert/sls_root_account_logins_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_root_account_logins_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins import ( + sls_alert_root_account_logins, + ) + + check = sls_alert_root_account_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-root-login-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins import ( + sls_alert_root_account_logins, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Root Account Logins", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_root_account_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Root Account Logins" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-root-login-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_root_account_logins.sls_alert_root_account_logins import ( + sls_alert_root_account_logins, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Root Account Logins", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_root_account_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_security_center_log_analysis/__init__.py b/tests/providers/alibabacloud/services/sls/sls_security_center_log_analysis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_security_center_log_analysis/sls_security_center_log_analysis_test.py b/tests/providers/alibabacloud/services/sls/sls_security_center_log_analysis/sls_security_center_log_analysis_test.py new file mode 100644 index 0000000000..de6124cc0b --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_security_center_log_analysis/sls_security_center_log_analysis_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_security_center_log_analysis: + def test_sls_security_center_log_analysis_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_security_center_log_analysis.sls_security_center_log_analysis.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_security_center_log_analysis.sls_security_center_log_analysis import ( + sls_security_center_log_analysis, + ) + + check = sls_security_center_log_analysis() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "Security Center Log Analysis" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_security_group_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_security_group_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_security_group_changes_alert/sls_security_group_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_security_group_changes_alert/sls_security_group_changes_alert_test.py new file mode 100644 index 0000000000..84efa1970c --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_security_group_changes_alert/sls_security_group_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_security_group_changes_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes import ( + sls_alert_security_group_changes, + ) + + check = sls_alert_security_group_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-security-group-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes import ( + sls_alert_security_group_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Security Group Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_security_group_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Security Group Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-security-group-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_security_group_changes.sls_alert_security_group_changes import ( + sls_alert_security_group_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Security Group Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_security_group_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_service_test.py b/tests/providers/alibabacloud/services/sls/sls_service_test.py new file mode 100644 index 0000000000..552b56d5fc --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_service_test.py @@ -0,0 +1,76 @@ +from unittest.mock import patch +from prowler.providers.alibabacloud.services.sls.sls_service import SLS, Project, Logstore +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_SLS_Service: + def test_service(self): + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ): + sls = SLS(set_mocked_alibabacloud_provider()) + + assert sls.service == "sls" + assert sls.account_id == ALIBABACLOUD_ACCOUNT_ID + assert sls.region == ALIBABACLOUD_REGION + assert len(sls.regions) > 0 + + def test_project_creation(self): + project_name = "test-project" + region = ALIBABACLOUD_REGION + arn = f"acs:sls:{region}:{ALIBABACLOUD_ACCOUNT_ID}:project/{project_name}" + + project = Project( + project_name=project_name, + arn=arn, + region=region, + description="Test project", + status="Normal" + ) + + assert project.project_name == project_name + assert project.arn == arn + assert project.region == region + assert project.description == "Test project" + assert project.status == "Normal" + + def test_logstore_creation(self): + project_name = "test-project" + logstore_name = "test-logstore" + region = ALIBABACLOUD_REGION + arn = f"acs:sls:{region}:{ALIBABACLOUD_ACCOUNT_ID}:logstore/{project_name}/{logstore_name}" + + logstore = Logstore( + logstore_name=logstore_name, + project_name=project_name, + arn=arn, + region=region, + ttl=90, + shard_count=4, + enable_tracking=True, + encrypt_conf={"enable": True, "encrypt_type": "default"} + ) + + assert logstore.logstore_name == logstore_name + assert logstore.project_name == project_name + assert logstore.arn == arn + assert logstore.region == region + assert logstore.ttl == 90 + assert logstore.shard_count == 4 + assert logstore.enable_tracking is True + assert logstore.encrypt_conf["enable"] is True + + def test_logstore_default_encrypt_conf(self): + logstore = Logstore( + logstore_name="test", + project_name="test-project", + arn="arn", + region=ALIBABACLOUD_REGION + ) + + assert logstore.encrypt_conf == {"enable": False} diff --git a/tests/providers/alibabacloud/services/sls/sls_single_factor_logins_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_single_factor_logins_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_single_factor_logins_alert/sls_single_factor_logins_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_single_factor_logins_alert/sls_single_factor_logins_alert_test.py new file mode 100644 index 0000000000..323dd63a70 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_single_factor_logins_alert/sls_single_factor_logins_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_alert_single_factor_logins: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins import ( + sls_alert_single_factor_logins, + ) + + check = sls_alert_single_factor_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-single-factor-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins import ( + sls_alert_single_factor_logins, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Single-Factor Console Logins", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_single_factor_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Single-Factor Console Logins" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-single-factor-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_single_factor_logins.sls_alert_single_factor_logins import ( + sls_alert_single_factor_logins, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Single-Factor Console Logins", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_single_factor_logins() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_unauthorized_api_calls_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_unauthorized_api_calls_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_unauthorized_api_calls_alert/sls_unauthorized_api_calls_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_unauthorized_api_calls_alert/sls_unauthorized_api_calls_alert_test.py new file mode 100644 index 0000000000..413ed25eb8 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_unauthorized_api_calls_alert/sls_unauthorized_api_calls_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_unauthorized_api_calls_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls import ( + sls_alert_unauthorized_api_calls, + ) + + check = sls_alert_unauthorized_api_calls() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-unauthorized-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls import ( + sls_alert_unauthorized_api_calls, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Unauthorized API Calls", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_unauthorized_api_calls() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "Unauthorized API Calls" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-unauthorized-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_unauthorized_api_calls.sls_alert_unauthorized_api_calls import ( + sls_alert_unauthorized_api_calls, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for Unauthorized API Calls", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_unauthorized_api_calls() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_vpc_config_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_vpc_config_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_vpc_config_changes_alert/sls_vpc_config_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_vpc_config_changes_alert/sls_vpc_config_changes_alert_test.py new file mode 100644 index 0000000000..db72d802f3 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_vpc_config_changes_alert/sls_vpc_config_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_vpc_config_changes_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes import ( + sls_alert_vpc_config_changes, + ) + + check = sls_alert_vpc_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-vpc-config-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes import ( + sls_alert_vpc_config_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for VPC Configuration Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_vpc_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "VPC Configuration Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-vpc-config-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_config_changes.sls_alert_vpc_config_changes import ( + sls_alert_vpc_config_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for VPC Configuration Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_vpc_config_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_vpc_route_changes_alert/__init__.py b/tests/providers/alibabacloud/services/sls/sls_vpc_route_changes_alert/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_vpc_route_changes_alert/sls_vpc_route_changes_alert_test.py b/tests/providers/alibabacloud/services/sls/sls_vpc_route_changes_alert/sls_vpc_route_changes_alert_test.py new file mode 100644 index 0000000000..45531b6001 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_vpc_route_changes_alert/sls_vpc_route_changes_alert_test.py @@ -0,0 +1,118 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_vpc_route_changes_alert: + def test_no_alerts(self): + sls_client = mock.MagicMock + sls_client.alerts = {} + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes import ( + sls_alert_vpc_route_changes, + ) + + check = sls_alert_vpc_route_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended + + def test_alert_enabled_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-vpc-route-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes import ( + sls_alert_vpc_route_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for VPC Route Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Enabled", + ) + } + + check = sls_alert_vpc_route_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "1 enabled alert" in result[0].status_extended + assert "VPC Route Changes" in result[0].status_extended + + def test_alert_disabled_fail(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + project_name = "test-project" + alert_name = "test-vpc-route-alert" + alert_arn = f"acs:sls:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:alert/{project_name}/{alert_name}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_alert_vpc_route_changes.sls_alert_vpc_route_changes import ( + sls_alert_vpc_route_changes, + ) + from prowler.providers.alibabacloud.services.sls.sls_service import Alert + + sls_client.alerts = { + alert_arn: Alert( + name=alert_name, + display_name="Alert for VPC Route Changes", + project_name=project_name, + arn=alert_arn, + region=ALIBABACLOUD_REGION, + state="Disabled", + ) + } + + check = sls_alert_vpc_route_changes() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == "sls-alerts" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "No enabled alerts found" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/sls/sls_waf_log_service/__init__.py b/tests/providers/alibabacloud/services/sls/sls_waf_log_service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/sls/sls_waf_log_service/sls_waf_log_service_test.py b/tests/providers/alibabacloud/services/sls/sls_waf_log_service/sls_waf_log_service_test.py new file mode 100644 index 0000000000..0a7d4f1334 --- /dev/null +++ b/tests/providers/alibabacloud/services/sls/sls_waf_log_service/sls_waf_log_service_test.py @@ -0,0 +1,33 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + set_mocked_alibabacloud_provider, +) + + +class Test_sls_waf_log_service: + def test_sls_waf_log_service_pass(self): + sls_client = mock.MagicMock + sls_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.sls.sls_waf_log_service.sls_waf_log_service.sls_client", + new=sls_client, + ): + from prowler.providers.alibabacloud.services.sls.sls_waf_log_service.sls_waf_log_service import ( + sls_waf_log_service, + ) + + check = sls_waf_log_service() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == "sls-integration" + assert result[0].account_uid == ALIBABACLOUD_ACCOUNT_ID + assert result[0].region == "global" + assert "WAF Log Service" in result[0].status_extended diff --git a/tests/providers/alibabacloud/services/vpc/__init__.py b/tests/providers/alibabacloud/services/vpc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/__init__.py b/tests/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use_test.py b/tests/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use_test.py new file mode 100644 index 0000000000..2a3dd075e1 --- /dev/null +++ b/tests/providers/alibabacloud/services/vpc/vpc_default_vpc_in_use/vpc_default_vpc_in_use_test.py @@ -0,0 +1,106 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_vpc_default_vpc_in_use: + def test_no_vpcs(self): + vpc_client = mock.MagicMock + vpc_client.vpcs = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use import ( + vpc_default_vpc_in_use, + ) + + check = vpc_default_vpc_in_use() + result = check.execute() + assert len(result) == 0 + + def test_vpc_not_default(self): + vpc_client = mock.MagicMock + vpc_id = "vpc-custom123" + vpc_arn = f"acs:vpc:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:vpc/{vpc_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use import ( + vpc_default_vpc_in_use, + ) + from prowler.providers.alibabacloud.services.vpc.vpc_service import VPC + + vpc_client.vpcs = { + vpc_arn: VPC( + vpc_id=vpc_id, + vpc_name="custom-vpc", + arn=vpc_arn, + region=ALIBABACLOUD_REGION, + cidr_block="172.16.0.0/12", + status="Available", + is_default=False, + ) + } + vpc_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = vpc_default_vpc_in_use() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == vpc_id + assert result[0].resource_arn == vpc_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_vpc_is_default(self): + vpc_client = mock.MagicMock + vpc_id = "vpc-default123" + vpc_arn = f"acs:vpc:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:vpc/{vpc_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_default_vpc_in_use.vpc_default_vpc_in_use import ( + vpc_default_vpc_in_use, + ) + from prowler.providers.alibabacloud.services.vpc.vpc_service import VPC + + vpc_client.vpcs = { + vpc_arn: VPC( + vpc_id=vpc_id, + vpc_name="default-vpc", + arn=vpc_arn, + region=ALIBABACLOUD_REGION, + cidr_block="172.16.0.0/12", + status="Available", + is_default=True, + ) + } + vpc_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = vpc_default_vpc_in_use() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == vpc_id + assert result[0].resource_arn == vpc_arn + assert result[0].region == ALIBABACLOUD_REGION diff --git a/tests/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/__init__.py b/tests/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled_test.py b/tests/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled_test.py new file mode 100644 index 0000000000..274da2c7fc --- /dev/null +++ b/tests/providers/alibabacloud/services/vpc/vpc_flow_logs_enabled/vpc_flow_logs_enabled_test.py @@ -0,0 +1,124 @@ +from unittest import mock + +from tests.providers.alibabacloud.alibabacloud_fixtures import ( + ALIBABACLOUD_ACCOUNT_ID, + ALIBABACLOUD_REGION, + set_mocked_alibabacloud_provider, +) + + +class Test_vpc_flow_logs_enabled: + def test_no_vpcs(self): + vpc_client = mock.MagicMock + vpc_client.vpcs = {} + vpc_client.flow_logs = {} + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled import ( + vpc_flow_logs_enabled, + ) + + check = vpc_flow_logs_enabled() + result = check.execute() + assert len(result) == 0 + + def test_vpc_with_flow_logs(self): + vpc_client = mock.MagicMock + vpc_id = "vpc-test123" + vpc_arn = f"acs:vpc:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:vpc/{vpc_id}" + flow_log_id = "fl-test123" + flow_log_arn = f"acs:vpc:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:flowlog/{flow_log_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled import ( + vpc_flow_logs_enabled, + ) + from prowler.providers.alibabacloud.services.vpc.vpc_service import ( + FlowLog, + VPC, + ) + + vpc_client.vpcs = { + vpc_arn: VPC( + vpc_id=vpc_id, + vpc_name="test-vpc", + arn=vpc_arn, + region=ALIBABACLOUD_REGION, + cidr_block="172.16.0.0/12", + status="Available", + is_default=False, + ) + } + vpc_client.flow_logs = { + flow_log_arn: FlowLog( + flow_log_id=flow_log_id, + flow_log_name="test-flow-log", + arn=flow_log_arn, + region=ALIBABACLOUD_REGION, + resource_type="VPC", + resource_id=vpc_id, + status="Active", + ) + } + vpc_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = vpc_flow_logs_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == vpc_id + assert result[0].resource_arn == vpc_arn + assert result[0].region == ALIBABACLOUD_REGION + + def test_vpc_without_flow_logs(self): + vpc_client = mock.MagicMock + vpc_id = "vpc-test456" + vpc_arn = f"acs:vpc:{ALIBABACLOUD_REGION}:{ALIBABACLOUD_ACCOUNT_ID}:vpc/{vpc_id}" + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_alibabacloud_provider(), + ), mock.patch( + "prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled.vpc_client", + new=vpc_client, + ): + from prowler.providers.alibabacloud.services.vpc.vpc_flow_logs_enabled.vpc_flow_logs_enabled import ( + vpc_flow_logs_enabled, + ) + from prowler.providers.alibabacloud.services.vpc.vpc_service import VPC + + vpc_client.vpcs = { + vpc_arn: VPC( + vpc_id=vpc_id, + vpc_name="test-vpc-no-logs", + arn=vpc_arn, + region=ALIBABACLOUD_REGION, + cidr_block="172.16.0.0/12", + status="Available", + is_default=False, + ) + } + vpc_client.flow_logs = {} + vpc_client.account_id = ALIBABACLOUD_ACCOUNT_ID + + check = vpc_flow_logs_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == vpc_id + assert result[0].resource_arn == vpc_arn + assert result[0].region == ALIBABACLOUD_REGION