prowler-cloud 5.17.1__py3-none-any.whl → 5.18.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dashboard/compliance/hipaa_azure.py +25 -0
- dashboard/pages/overview.py +20 -11
- prowler/AGENTS.md +1 -1
- prowler/CHANGELOG.md +43 -0
- prowler/__main__.py +5 -0
- prowler/compliance/azure/hipaa_azure.json +820 -0
- prowler/compliance/m365/cis_4.0_m365.json +6 -2
- prowler/compliance/m365/cis_6.0_m365.json +6 -2
- prowler/compliance/m365/iso27001_2022_m365.json +13 -11
- prowler/compliance/openstack/__init__.py +0 -0
- prowler/config/config.py +2 -1
- prowler/config/config.yaml +4 -1
- prowler/config/openstack_mutelist_example.yaml +60 -0
- prowler/lib/check/check.py +4 -0
- prowler/lib/check/models.py +27 -2
- prowler/lib/cli/parser.py +3 -2
- prowler/lib/outputs/finding.py +14 -0
- prowler/lib/outputs/html/html.py +72 -0
- prowler/lib/outputs/jira/jira.py +3 -3
- prowler/lib/outputs/outputs.py +2 -0
- prowler/lib/outputs/summary_table.py +7 -0
- prowler/lib/timeline/__init__.py +0 -0
- prowler/lib/timeline/models.py +27 -0
- prowler/lib/timeline/timeline.py +36 -0
- prowler/providers/aws/lib/cloudtrail_timeline/__init__.py +0 -0
- prowler/providers/aws/lib/cloudtrail_timeline/cloudtrail_timeline.py +218 -0
- prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/__init__.py +0 -0
- prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.metadata.json +40 -0
- prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.py +58 -0
- prowler/providers/aws/services/codebuild/codebuild_service.py +45 -0
- prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.metadata.json +1 -1
- prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py +4 -0
- prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.metadata.json +1 -1
- prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.py +4 -0
- prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.metadata.json +1 -1
- prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.py +2 -0
- prowler/providers/aws/services/iam/lib/policy.py +19 -3
- prowler/providers/aws/services/rds/rds_instance_extended_support/__init__.py +0 -0
- prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.metadata.json +41 -0
- prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.py +37 -0
- prowler/providers/aws/services/rds/rds_service.py +4 -0
- prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json +1 -1
- prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.py +5 -1
- prowler/providers/azure/lib/service/service.py +23 -0
- prowler/providers/azure/services/app/app_client_certificates_on/app_client_certificates_on.metadata.json +18 -12
- prowler/providers/azure/services/app/app_ensure_auth_is_set_up/app_ensure_auth_is_set_up.metadata.json +18 -11
- prowler/providers/azure/services/app/app_ensure_http_is_redirected_to_https/app_ensure_http_is_redirected_to_https.metadata.json +19 -12
- prowler/providers/azure/services/app/app_ensure_java_version_is_latest/app_ensure_java_version_is_latest.metadata.json +19 -12
- prowler/providers/azure/services/app/app_ensure_php_version_is_latest/app_ensure_php_version_is_latest.metadata.json +19 -12
- prowler/providers/azure/services/app/app_ensure_python_version_is_latest/app_ensure_python_version_is_latest.metadata.json +19 -12
- prowler/providers/azure/services/app/app_ensure_using_http20/app_ensure_using_http20.metadata.json +18 -11
- prowler/providers/azure/services/app/app_ftp_deployment_disabled/app_ftp_deployment_disabled.metadata.json +21 -13
- prowler/providers/azure/services/app/app_function_access_keys_configured/app_function_access_keys_configured.metadata.json +19 -11
- prowler/providers/azure/services/app/app_function_application_insights_enabled/app_function_application_insights_enabled.metadata.json +21 -14
- prowler/providers/azure/services/app/app_function_ftps_deployment_disabled/app_function_ftps_deployment_disabled.metadata.json +18 -13
- prowler/providers/azure/services/app/app_function_identity_is_configured/app_function_identity_is_configured.metadata.json +20 -13
- prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.metadata.json +18 -11
- prowler/providers/azure/services/app/app_function_latest_runtime_version/app_function_latest_runtime_version.metadata.json +20 -13
- prowler/providers/azure/services/app/app_function_not_publicly_accessible/app_function_not_publicly_accessible.metadata.json +20 -13
- prowler/providers/azure/services/app/app_function_vnet_integration_enabled/app_function_vnet_integration_enabled.metadata.json +21 -14
- prowler/providers/azure/services/app/app_http_logs_enabled/app_http_logs_enabled.metadata.json +18 -12
- prowler/providers/azure/services/app/app_minimum_tls_version_12/app_minimum_tls_version_12.metadata.json +20 -12
- prowler/providers/azure/services/app/app_register_with_identity/app_register_with_identity.metadata.json +18 -11
- prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.metadata.json +18 -12
- prowler/providers/azure/services/containerregistry/containerregistry_admin_user_disabled/containerregistry_admin_user_disabled.metadata.json +17 -11
- prowler/providers/azure/services/containerregistry/containerregistry_not_publicly_accessible/containerregistry_not_publicly_accessible.metadata.json +18 -12
- prowler/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link.metadata.json +21 -13
- prowler/providers/azure/services/cosmosdb/cosmosdb_account_firewall_use_selected_networks/cosmosdb_account_firewall_use_selected_networks.metadata.json +20 -12
- prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/cosmosdb_account_use_aad_and_rbac.metadata.json +19 -13
- prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_private_endpoints/cosmosdb_account_use_private_endpoints.metadata.json +20 -13
- prowler/providers/azure/services/databricks/databricks_workspace_cmk_encryption_enabled/databricks_workspace_cmk_encryption_enabled.metadata.json +20 -14
- prowler/providers/azure/services/databricks/databricks_workspace_vnet_injection_enabled/databricks_workspace_vnet_injection_enabled.metadata.json +20 -14
- prowler/providers/azure/services/defender/defender_additional_email_configured_with_a_security_contact/defender_additional_email_configured_with_a_security_contact.metadata.json +20 -13
- prowler/providers/azure/services/defender/defender_assessments_vm_endpoint_protection_installed/defender_assessments_vm_endpoint_protection_installed.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_attack_path_notifications_properly_configured/defender_attack_path_notifications_properly_configured.metadata.json +19 -13
- prowler/providers/azure/services/defender/defender_auto_provisioning_log_analytics_agent_vms_on/defender_auto_provisioning_log_analytics_agent_vms_on.metadata.json +20 -13
- prowler/providers/azure/services/defender/defender_auto_provisioning_vulnerabilty_assessments_machines_on/defender_auto_provisioning_vulnerabilty_assessments_machines_on.metadata.json +19 -12
- prowler/providers/azure/services/defender/defender_container_images_resolved_vulnerabilities/defender_container_images_resolved_vulnerabilities.metadata.json +20 -12
- prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.metadata.json +22 -13
- prowler/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on.metadata.json +19 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.metadata.json +17 -11
- prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.metadata.json +20 -12
- prowler/providers/azure/services/defender/defender_ensure_notify_alerts_severity_is_high/defender_ensure_notify_alerts_severity_is_high.metadata.json +19 -12
- prowler/providers/azure/services/defender/defender_ensure_notify_emails_to_owners/defender_ensure_notify_emails_to_owners.metadata.json +19 -12
- prowler/providers/azure/services/defender/defender_ensure_system_updates_are_applied/defender_ensure_system_updates_are_applied.metadata.json +17 -9
- prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.metadata.json +21 -13
- prowler/providers/azure/services/entra/entra_service.py +3 -11
- prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py +6 -0
- prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.metadata.json +19 -13
- prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json +16 -10
- prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.metadata.json +18 -12
- prowler/providers/azure/services/keyvault/keyvault_rbac_secret_expiration_set/keyvault_rbac_secret_expiration_set.py +10 -11
- prowler/providers/azure/services/keyvault/keyvault_service.py +164 -81
- prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_connection_activated/mysql_flexible_server_audit_log_connection_activated.metadata.json +18 -12
- prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_enabled/mysql_flexible_server_audit_log_enabled.metadata.json +19 -12
- prowler/providers/azure/services/mysql/mysql_flexible_server_minimum_tls_version_12/mysql_flexible_server_minimum_tls_version_12.metadata.json +18 -12
- prowler/providers/azure/services/mysql/mysql_flexible_server_ssl_connection_enabled/mysql_flexible_server_ssl_connection_enabled.metadata.json +19 -12
- prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.metadata.json +21 -12
- prowler/providers/azure/services/network/network_flow_log_captured_sent/network_flow_log_captured_sent.metadata.json +19 -12
- prowler/providers/azure/services/network/network_flow_log_more_than_90_days/network_flow_log_more_than_90_days.metadata.json +21 -12
- prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.metadata.json +18 -12
- prowler/providers/azure/services/network/network_public_ip_shodan/network_public_ip_shodan.metadata.json +15 -10
- prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.metadata.json +20 -12
- prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.metadata.json +19 -12
- prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.metadata.json +19 -12
- prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.metadata.json +21 -13
- prowler/providers/azure/services/policy/policy_ensure_asc_enforcement_enabled/policy_ensure_asc_enforcement_enabled.metadata.json +16 -11
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_allow_access_services_disabled/postgresql_flexible_server_allow_access_services_disabled.metadata.json +20 -13
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_connection_throttling_on/postgresql_flexible_server_connection_throttling_on.metadata.json +18 -12
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_enforce_ssl_enabled/postgresql_flexible_server_enforce_ssl_enabled.metadata.json +19 -13
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_entra_id_authentication_enabled/postgresql_flexible_server_entra_id_authentication_enabled.metadata.json +4 -4
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_checkpoints_on/postgresql_flexible_server_log_checkpoints_on.metadata.json +19 -13
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_connections_on/postgresql_flexible_server_log_connections_on.metadata.json +18 -11
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_disconnections_on/postgresql_flexible_server_log_disconnections_on.metadata.json +18 -12
- prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_retention_days_greater_3/postgresql_flexible_server_log_retention_days_greater_3.metadata.json +18 -12
- prowler/providers/azure/services/sqlserver/sqlserver_auditing_enabled/sqlserver_auditing_enabled.metadata.json +20 -13
- prowler/providers/azure/services/sqlserver/sqlserver_auditing_retention_90_days/sqlserver_auditing_retention_90_days.metadata.json +20 -12
- prowler/providers/azure/services/sqlserver/sqlserver_azuread_administrator_enabled/sqlserver_azuread_administrator_enabled.metadata.json +18 -12
- prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json +23 -13
- prowler/providers/azure/services/sqlserver/sqlserver_recommended_minimal_tls_version/sqlserver_recommended_minimal_tls_version.metadata.json +19 -12
- prowler/providers/azure/services/sqlserver/sqlserver_tde_encrypted_with_cmk/sqlserver_tde_encrypted_with_cmk.metadata.json +20 -13
- prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json +20 -13
- prowler/providers/azure/services/sqlserver/sqlserver_unrestricted_inbound_access/sqlserver_unrestricted_inbound_access.metadata.json +18 -12
- prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json +19 -12
- prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json +19 -12
- prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json +18 -12
- prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled/sqlserver_vulnerability_assessment_enabled.metadata.json +19 -12
- prowler/providers/azure/services/storage/storage_account_key_access_disabled/storage_account_key_access_disabled.metadata.json +17 -12
- prowler/providers/azure/services/storage/storage_blob_public_access_level_is_disabled/storage_blob_public_access_level_is_disabled.metadata.json +18 -12
- prowler/providers/azure/services/storage/storage_blob_versioning_is_enabled/storage_blob_versioning_is_enabled.metadata.json +19 -11
- prowler/providers/azure/services/storage/storage_cross_tenant_replication_disabled/storage_cross_tenant_replication_disabled.metadata.json +19 -13
- prowler/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied.metadata.json +19 -12
- prowler/providers/azure/services/storage/storage_default_to_entra_authorization_enabled/storage_default_to_entra_authorization_enabled.metadata.json +20 -13
- prowler/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled.metadata.json +17 -10
- prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys/storage_ensure_encryption_with_customer_managed_keys.metadata.json +15 -10
- prowler/providers/azure/services/storage/storage_ensure_file_shares_soft_delete_is_enabled/storage_ensure_file_shares_soft_delete_is_enabled.metadata.json +18 -12
- prowler/providers/azure/services/storage/storage_ensure_minimum_tls_version_12/storage_ensure_minimum_tls_version_12.metadata.json +14 -10
- prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts.metadata.json +19 -11
- prowler/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled.metadata.json +17 -12
- prowler/providers/azure/services/storage/storage_geo_redundant_enabled/storage_geo_redundant_enabled.metadata.json +19 -12
- prowler/providers/azure/services/storage/storage_infrastructure_encryption_is_enabled/storage_infrastructure_encryption_is_enabled.metadata.json +13 -9
- prowler/providers/azure/services/storage/storage_key_rotation_90_days/storage_key_rotation_90_days.metadata.json +17 -12
- prowler/providers/azure/services/storage/storage_secure_transfer_required_is_enabled/storage_secure_transfer_required_is_enabled.metadata.json +15 -11
- prowler/providers/azure/services/storage/storage_smb_channel_encryption_with_secure_algorithm/storage_smb_channel_encryption_with_secure_algorithm.metadata.json +19 -12
- prowler/providers/azure/services/storage/storage_smb_protocol_version_is_latest/storage_smb_protocol_version_is_latest.metadata.json +19 -13
- prowler/providers/cloudflare/cloudflare_provider.py +95 -12
- prowler/providers/cloudflare/lib/arguments/arguments.py +7 -0
- prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/__init__.py +0 -0
- prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.metadata.json +36 -0
- prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.py +109 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/__init__.py +0 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.metadata.json +36 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.py +73 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/__init__.py +0 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.metadata.json +36 -0
- prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.py +60 -0
- prowler/providers/cloudflare/services/dns/dns_record_proxied/__init__.py +0 -0
- prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.metadata.json +36 -0
- prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.py +49 -0
- prowler/providers/cloudflare/services/dns/dns_service.py +52 -6
- prowler/providers/cloudflare/services/firewall/__init__.py +0 -0
- prowler/providers/cloudflare/services/firewall/firewall_client.py +4 -0
- prowler/providers/cloudflare/services/firewall/firewall_service.py +123 -0
- prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/__init__.py +0 -0
- prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.metadata.json +36 -0
- prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.py +53 -0
- prowler/providers/cloudflare/services/zone/zone_service.py +133 -1
- prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/__init__.py +0 -0
- prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.metadata.json +36 -0
- prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.py +58 -0
- prowler/providers/common/provider.py +23 -0
- prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/__init__.py +0 -0
- prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.metadata.json +37 -0
- prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.py +35 -0
- prowler/providers/gcp/services/compute/compute_service.py +2 -0
- prowler/providers/m365/lib/powershell/m365_powershell.py +47 -1
- prowler/providers/m365/services/defender/defender_service.py +52 -0
- prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/__init__.py +0 -0
- prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.metadata.json +38 -0
- prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.py +53 -0
- prowler/providers/m365/services/exchange/exchange_service.py +78 -0
- prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/__init__.py +0 -0
- prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.metadata.json +37 -0
- prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.py +59 -0
- prowler/providers/openstack/__init__.py +0 -0
- prowler/providers/openstack/exceptions/__init__.py +0 -0
- prowler/providers/openstack/exceptions/exceptions.py +166 -0
- prowler/providers/openstack/lib/__init__.py +0 -0
- prowler/providers/openstack/lib/arguments/__init__.py +0 -0
- prowler/providers/openstack/lib/arguments/arguments.py +113 -0
- prowler/providers/openstack/lib/mutelist/__init__.py +0 -0
- prowler/providers/openstack/lib/mutelist/mutelist.py +31 -0
- prowler/providers/openstack/lib/service/__init__.py +0 -0
- prowler/providers/openstack/lib/service/service.py +21 -0
- prowler/providers/openstack/models.py +100 -0
- prowler/providers/openstack/openstack_provider.py +515 -0
- prowler/providers/openstack/services/__init__.py +0 -0
- prowler/providers/openstack/services/compute/__init__.py +0 -0
- prowler/providers/openstack/services/compute/compute_client.py +4 -0
- prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/__init__.py +0 -0
- prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.metadata.json +40 -0
- prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.py +35 -0
- prowler/providers/openstack/services/compute/compute_service.py +63 -0
- {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/METADATA +11 -9
- {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/RECORD +219 -155
- {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/LICENSE +0 -0
- {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/WHEEL +0 -0
- {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from prowler.lib.check.models import Check, Check_Report_GCP
|
|
2
|
+
from prowler.providers.gcp.services.compute.compute_client import compute_client
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class compute_instance_suspended_without_persistent_disks(Check):
|
|
6
|
+
"""
|
|
7
|
+
Ensure that VM instances in SUSPENDED state do not have persistent disks attached.
|
|
8
|
+
|
|
9
|
+
This check identifies VM instances that are in a SUSPENDED or SUSPENDING state
|
|
10
|
+
and have persistent disks still attached. Suspended VMs with attached disks
|
|
11
|
+
represent unused infrastructure that continues to incur storage costs.
|
|
12
|
+
|
|
13
|
+
- PASS: VM instance is not in SUSPENDED/SUSPENDING state, or is suspended but has no disks attached.
|
|
14
|
+
- FAIL: VM instance is in SUSPENDED/SUSPENDING state with persistent disks attached.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def execute(self) -> list[Check_Report_GCP]:
|
|
18
|
+
findings = []
|
|
19
|
+
for instance in compute_client.instances:
|
|
20
|
+
report = Check_Report_GCP(metadata=self.metadata(), resource=instance)
|
|
21
|
+
report.status = "PASS"
|
|
22
|
+
report.status_extended = f"VM Instance {instance.name} is not suspended."
|
|
23
|
+
|
|
24
|
+
if instance.status in ("SUSPENDED", "SUSPENDING"):
|
|
25
|
+
attached_disks = [disk.name for disk in instance.disks]
|
|
26
|
+
|
|
27
|
+
if attached_disks:
|
|
28
|
+
report.status = "FAIL"
|
|
29
|
+
report.status_extended = f"VM Instance {instance.name} is {instance.status.lower()} with {len(attached_disks)} persistent disk(s) attached: {', '.join(attached_disks)}."
|
|
30
|
+
else:
|
|
31
|
+
report.status_extended = f"VM Instance {instance.name} is {instance.status.lower()} but has no persistent disks attached."
|
|
32
|
+
|
|
33
|
+
findings.append(report)
|
|
34
|
+
|
|
35
|
+
return findings
|
|
@@ -198,6 +198,7 @@ class Compute(GCPService):
|
|
|
198
198
|
"deletionProtection", False
|
|
199
199
|
),
|
|
200
200
|
network_interfaces=network_interfaces,
|
|
201
|
+
status=instance.get("status", "RUNNING"),
|
|
201
202
|
on_host_maintenance=instance.get("scheduling", {}).get(
|
|
202
203
|
"onHostMaintenance", "MIGRATE"
|
|
203
204
|
),
|
|
@@ -700,6 +701,7 @@ class Instance(BaseModel):
|
|
|
700
701
|
provisioning_model: str = "STANDARD"
|
|
701
702
|
deletion_protection: bool = False
|
|
702
703
|
network_interfaces: list[NetworkInterface] = []
|
|
704
|
+
status: str = "RUNNING"
|
|
703
705
|
on_host_maintenance: str = "MIGRATE"
|
|
704
706
|
|
|
705
707
|
|
|
@@ -823,6 +823,52 @@ class M365PowerShell(PowerShellSession):
|
|
|
823
823
|
"Get-SharingPolicy | ConvertTo-Json -Depth 10", json_parse=True
|
|
824
824
|
)
|
|
825
825
|
|
|
826
|
+
def get_teams_protection_policy(self) -> dict:
|
|
827
|
+
"""
|
|
828
|
+
Get Teams Protection Policy.
|
|
829
|
+
|
|
830
|
+
Retrieves the Teams protection policy settings including Zero-hour auto purge (ZAP) configuration.
|
|
831
|
+
|
|
832
|
+
Returns:
|
|
833
|
+
dict: Teams protection policy settings in JSON format.
|
|
834
|
+
|
|
835
|
+
Example:
|
|
836
|
+
>>> get_teams_protection_policy()
|
|
837
|
+
{
|
|
838
|
+
"Identity": "Teams Protection Policy",
|
|
839
|
+
"ZapEnabled": True
|
|
840
|
+
}
|
|
841
|
+
"""
|
|
842
|
+
return self.execute(
|
|
843
|
+
"Get-TeamsProtectionPolicy | ConvertTo-Json -Depth 10", json_parse=True
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
def get_shared_mailboxes(self) -> dict:
|
|
847
|
+
"""
|
|
848
|
+
Get Exchange Online Shared Mailboxes.
|
|
849
|
+
|
|
850
|
+
Retrieves all shared mailboxes from Exchange Online with their external
|
|
851
|
+
directory object IDs for cross-referencing with Entra ID user accounts.
|
|
852
|
+
|
|
853
|
+
Returns:
|
|
854
|
+
dict: Shared mailbox information in JSON format.
|
|
855
|
+
|
|
856
|
+
Example:
|
|
857
|
+
>>> get_shared_mailboxes()
|
|
858
|
+
[
|
|
859
|
+
{
|
|
860
|
+
"DisplayName": "Support Mailbox",
|
|
861
|
+
"UserPrincipalName": "support@contoso.com",
|
|
862
|
+
"ExternalDirectoryObjectId": "12345678-1234-1234-1234-123456789012",
|
|
863
|
+
"Identity": "support@contoso.com"
|
|
864
|
+
}
|
|
865
|
+
]
|
|
866
|
+
"""
|
|
867
|
+
return self.execute(
|
|
868
|
+
"Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited | Select-Object DisplayName, UserPrincipalName, ExternalDirectoryObjectId, Identity | ConvertTo-Json -Depth 10",
|
|
869
|
+
json_parse=True,
|
|
870
|
+
)
|
|
871
|
+
|
|
826
872
|
def get_user_account_status(self) -> dict:
|
|
827
873
|
"""
|
|
828
874
|
Get User Account Status.
|
|
@@ -833,7 +879,7 @@ class M365PowerShell(PowerShellSession):
|
|
|
833
879
|
dict: User account status settings in JSON format.
|
|
834
880
|
"""
|
|
835
881
|
return self.execute(
|
|
836
|
-
"$dict=@{}; Get-User -ResultSize Unlimited | ForEach-Object { $dict[$_.
|
|
882
|
+
"$dict=@{}; Get-User -ResultSize Unlimited | ForEach-Object { $dict[$_.ExternalDirectoryObjectId] = @{ AccountDisabled = $_.AccountDisabled } }; $dict | ConvertTo-Json -Depth 10",
|
|
837
883
|
json_parse=True,
|
|
838
884
|
)
|
|
839
885
|
|
|
@@ -8,7 +8,20 @@ from prowler.providers.m365.m365_provider import M365Provider
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Defender(M365Service):
|
|
11
|
+
"""
|
|
12
|
+
Microsoft 365 Defender service implementation.
|
|
13
|
+
|
|
14
|
+
Provides access to Microsoft Defender for Office 365 configurations including
|
|
15
|
+
malware policies, spam filtering, anti-phishing, and Teams protection settings.
|
|
16
|
+
"""
|
|
17
|
+
|
|
11
18
|
def __init__(self, provider: M365Provider):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the Defender service.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
provider: The M365 provider instance.
|
|
24
|
+
"""
|
|
12
25
|
super().__init__(provider)
|
|
13
26
|
self.malware_policies = []
|
|
14
27
|
self.outbound_spam_policies = {}
|
|
@@ -20,6 +33,7 @@ class Defender(M365Service):
|
|
|
20
33
|
self.inbound_spam_policies = []
|
|
21
34
|
self.inbound_spam_rules = {}
|
|
22
35
|
self.report_submission_policy = None
|
|
36
|
+
self.teams_protection_policy = None
|
|
23
37
|
if self.powershell:
|
|
24
38
|
if self.powershell.connect_exchange_online():
|
|
25
39
|
self.malware_policies = self._get_malware_filter_policy()
|
|
@@ -33,6 +47,7 @@ class Defender(M365Service):
|
|
|
33
47
|
self.inbound_spam_policies = self._get_inbound_spam_filter_policy()
|
|
34
48
|
self.inbound_spam_rules = self._get_inbound_spam_filter_rule()
|
|
35
49
|
self.report_submission_policy = self._get_report_submission_policy()
|
|
50
|
+
self.teams_protection_policy = self._get_teams_protection_policy()
|
|
36
51
|
self.powershell.close()
|
|
37
52
|
|
|
38
53
|
def _get_malware_filter_policy(self):
|
|
@@ -350,6 +365,12 @@ class Defender(M365Service):
|
|
|
350
365
|
return inbound_spam_rules
|
|
351
366
|
|
|
352
367
|
def _get_report_submission_policy(self):
|
|
368
|
+
"""
|
|
369
|
+
Retrieve the Defender report submission policy.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
ReportSubmissionPolicy: The report submission policy configuration.
|
|
373
|
+
"""
|
|
353
374
|
logger.info("Microsoft365 - Getting Defender report submission policy...")
|
|
354
375
|
report_submission_policy = None
|
|
355
376
|
try:
|
|
@@ -387,6 +408,28 @@ class Defender(M365Service):
|
|
|
387
408
|
)
|
|
388
409
|
return report_submission_policy
|
|
389
410
|
|
|
411
|
+
def _get_teams_protection_policy(self):
|
|
412
|
+
"""
|
|
413
|
+
Retrieve the Teams protection policy including ZAP settings.
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
TeamsProtectionPolicy: The Teams protection policy configuration.
|
|
417
|
+
"""
|
|
418
|
+
logger.info("Microsoft365 - Getting Teams protection policy...")
|
|
419
|
+
teams_protection_policy = None
|
|
420
|
+
try:
|
|
421
|
+
policy = self.powershell.get_teams_protection_policy()
|
|
422
|
+
if policy:
|
|
423
|
+
teams_protection_policy = TeamsProtectionPolicy(
|
|
424
|
+
identity=policy.get("Identity", ""),
|
|
425
|
+
zap_enabled=policy.get("ZapEnabled", True),
|
|
426
|
+
)
|
|
427
|
+
except Exception as error:
|
|
428
|
+
logger.error(
|
|
429
|
+
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
|
430
|
+
)
|
|
431
|
+
return teams_protection_policy
|
|
432
|
+
|
|
390
433
|
|
|
391
434
|
class MalwarePolicy(BaseModel):
|
|
392
435
|
enable_file_filter: bool
|
|
@@ -470,6 +513,8 @@ class InboundSpamRule(BaseModel):
|
|
|
470
513
|
|
|
471
514
|
|
|
472
515
|
class ReportSubmissionPolicy(BaseModel):
|
|
516
|
+
"""Model for Defender report submission policy settings."""
|
|
517
|
+
|
|
473
518
|
report_junk_to_customized_address: bool
|
|
474
519
|
report_not_junk_to_customized_address: bool
|
|
475
520
|
report_phish_to_customized_address: bool
|
|
@@ -478,3 +523,10 @@ class ReportSubmissionPolicy(BaseModel):
|
|
|
478
523
|
report_phish_addresses: list[str]
|
|
479
524
|
report_chat_message_enabled: bool
|
|
480
525
|
report_chat_message_to_customized_address_enabled: bool
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
class TeamsProtectionPolicy(BaseModel):
|
|
529
|
+
"""Model for Teams protection policy settings including ZAP configuration."""
|
|
530
|
+
|
|
531
|
+
identity: str
|
|
532
|
+
zap_enabled: bool
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Provider": "m365",
|
|
3
|
+
"CheckID": "defender_zap_for_teams_enabled",
|
|
4
|
+
"CheckTitle": "Zero-hour auto purge (ZAP) protects Microsoft Teams from malware and phishing",
|
|
5
|
+
"CheckType": [],
|
|
6
|
+
"ServiceName": "defender",
|
|
7
|
+
"SubServiceName": "",
|
|
8
|
+
"ResourceIdTemplate": "",
|
|
9
|
+
"Severity": "medium",
|
|
10
|
+
"ResourceType": "Teams Protection Policy",
|
|
11
|
+
"ResourceGroup": "collaboration",
|
|
12
|
+
"Description": "Zero-hour auto purge (ZAP) is a protection feature that retroactively detects and neutralizes **malware** and **high confidence phishing** in Teams messages.\n\nWhen ZAP blocks a message, it is blocked for everyone in the chat. The initial block happens right after delivery, but ZAP can occur up to 48 hours after delivery.",
|
|
13
|
+
"Risk": "Without ZAP enabled, malicious content delivered to Teams chats remains accessible to users for up to 48 hours after delivery, even after being identified as harmful.\n\nThis extended exposure window could lead to:\n- **Malware infections** from weaponized attachments or links\n- **Phishing attacks** compromising user credentials and MFA tokens\n- **Lateral movement** as attackers exploit compromised accounts within the organization",
|
|
14
|
+
"RelatedUrl": "",
|
|
15
|
+
"AdditionalURLs": [
|
|
16
|
+
"https://learn.microsoft.com/en-us/defender-office-365/zero-hour-auto-purge?view=o365-worldwide#zero-hour-auto-purge-zap-in-microsoft-teams",
|
|
17
|
+
"https://learn.microsoft.com/en-us/defender-office-365/mdo-support-teams-about?view=o365-worldwide"
|
|
18
|
+
],
|
|
19
|
+
"Remediation": {
|
|
20
|
+
"Code": {
|
|
21
|
+
"CLI": "Set-TeamsProtectionPolicy -Identity 'Teams Protection Policy' -ZapEnabled $true",
|
|
22
|
+
"NativeIaC": "",
|
|
23
|
+
"Other": "1. Navigate to Microsoft Defender https://security.microsoft.com/\n2. Click to expand System and select Settings > Email & collaboration > Microsoft Teams protection\n3. Set Zero-hour auto purge (ZAP) to On (Default)",
|
|
24
|
+
"Terraform": ""
|
|
25
|
+
},
|
|
26
|
+
"Recommendation": {
|
|
27
|
+
"Text": "Enable Zero-hour auto purge (ZAP) for Microsoft Teams to ensure malicious content is automatically removed from chats after detection, even if it was delivered before being identified as harmful.",
|
|
28
|
+
"Url": "https://hub.prowler.com/check/defender_zap_for_teams_enabled"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"Categories": [
|
|
32
|
+
"email-security",
|
|
33
|
+
"e5"
|
|
34
|
+
],
|
|
35
|
+
"DependsOn": [],
|
|
36
|
+
"RelatedTo": [],
|
|
37
|
+
"Notes": ""
|
|
38
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from prowler.lib.check.models import Check, CheckReportM365
|
|
4
|
+
from prowler.providers.m365.services.defender.defender_client import defender_client
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class defender_zap_for_teams_enabled(Check):
|
|
8
|
+
"""Check if Zero-hour auto purge (ZAP) is enabled for Microsoft Teams.
|
|
9
|
+
|
|
10
|
+
ZAP is a protection feature that retroactively detects and neutralizes malware
|
|
11
|
+
and high confidence phishing in Teams messages.
|
|
12
|
+
|
|
13
|
+
- PASS: ZAP is enabled for Teams protection.
|
|
14
|
+
- FAIL: ZAP is not enabled for Teams protection.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
metadata: Metadata associated with the check (inherited from Check).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def execute(self) -> List[CheckReportM365]:
|
|
21
|
+
"""Execute the check for Teams ZAP protection status.
|
|
22
|
+
|
|
23
|
+
This method checks if Zero-hour auto purge (ZAP) is enabled for Microsoft Teams
|
|
24
|
+
to ensure malicious content is automatically removed from chats after detection.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
List[CheckReportM365]: A list of reports containing the result of the check.
|
|
28
|
+
"""
|
|
29
|
+
findings = []
|
|
30
|
+
teams_protection_policy = defender_client.teams_protection_policy
|
|
31
|
+
|
|
32
|
+
if teams_protection_policy:
|
|
33
|
+
report = CheckReportM365(
|
|
34
|
+
metadata=self.metadata(),
|
|
35
|
+
resource=teams_protection_policy,
|
|
36
|
+
resource_name="Teams Protection Policy",
|
|
37
|
+
resource_id="teamsProtectionPolicy",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if teams_protection_policy.zap_enabled:
|
|
41
|
+
report.status = "PASS"
|
|
42
|
+
report.status_extended = (
|
|
43
|
+
"Zero-hour auto purge (ZAP) is enabled for Microsoft Teams."
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
report.status = "FAIL"
|
|
47
|
+
report.status_extended = (
|
|
48
|
+
"Zero-hour auto purge (ZAP) is not enabled for Microsoft Teams."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
findings.append(report)
|
|
52
|
+
|
|
53
|
+
return findings
|
|
@@ -9,7 +9,20 @@ from prowler.providers.m365.m365_provider import M365Provider
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Exchange(M365Service):
|
|
12
|
+
"""
|
|
13
|
+
Exchange Online service for Microsoft 365.
|
|
14
|
+
|
|
15
|
+
This service provides access to Exchange Online resources and configurations
|
|
16
|
+
including organization settings, mailboxes, transport rules, and policies.
|
|
17
|
+
"""
|
|
18
|
+
|
|
12
19
|
def __init__(self, provider: M365Provider):
|
|
20
|
+
"""
|
|
21
|
+
Initialize the Exchange service.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
provider: The M365Provider instance for authentication and configuration.
|
|
25
|
+
"""
|
|
13
26
|
super().__init__(provider)
|
|
14
27
|
self.organization_config = None
|
|
15
28
|
self.mailboxes_config = []
|
|
@@ -19,6 +32,7 @@ class Exchange(M365Service):
|
|
|
19
32
|
self.mailbox_policies = []
|
|
20
33
|
self.role_assignment_policies = []
|
|
21
34
|
self.mailbox_audit_properties = []
|
|
35
|
+
self.shared_mailboxes = []
|
|
22
36
|
|
|
23
37
|
if self.powershell:
|
|
24
38
|
if self.powershell.connect_exchange_online():
|
|
@@ -30,6 +44,7 @@ class Exchange(M365Service):
|
|
|
30
44
|
self.mailbox_policies = self._get_mailbox_policy()
|
|
31
45
|
self.role_assignment_policies = self._get_role_assignment_policies()
|
|
32
46
|
self.mailbox_audit_properties = self._get_mailbox_audit_properties()
|
|
47
|
+
self.shared_mailboxes = self._get_shared_mailboxes()
|
|
33
48
|
self.powershell.close()
|
|
34
49
|
|
|
35
50
|
def _get_organization_config(self):
|
|
@@ -211,6 +226,12 @@ class Exchange(M365Service):
|
|
|
211
226
|
return role_assignment_policies
|
|
212
227
|
|
|
213
228
|
def _get_mailbox_audit_properties(self):
|
|
229
|
+
"""
|
|
230
|
+
Get mailbox audit properties for all mailboxes.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
list[MailboxAuditProperties]: List of mailbox audit property configurations.
|
|
234
|
+
"""
|
|
214
235
|
logger.info("Microsoft365 - Getting mailbox audit properties...")
|
|
215
236
|
mailbox_audit_properties = []
|
|
216
237
|
try:
|
|
@@ -248,6 +269,44 @@ class Exchange(M365Service):
|
|
|
248
269
|
)
|
|
249
270
|
return mailbox_audit_properties
|
|
250
271
|
|
|
272
|
+
def _get_shared_mailboxes(self):
|
|
273
|
+
"""
|
|
274
|
+
Get all shared mailboxes from Exchange Online.
|
|
275
|
+
|
|
276
|
+
Retrieves shared mailboxes with their external directory object IDs
|
|
277
|
+
for cross-referencing with Entra ID user accounts.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
list[SharedMailbox]: List of shared mailbox configurations.
|
|
281
|
+
"""
|
|
282
|
+
logger.info("Microsoft365 - Getting shared mailboxes...")
|
|
283
|
+
shared_mailboxes = []
|
|
284
|
+
try:
|
|
285
|
+
shared_mailboxes_data = self.powershell.get_shared_mailboxes()
|
|
286
|
+
if not shared_mailboxes_data:
|
|
287
|
+
return shared_mailboxes
|
|
288
|
+
if isinstance(shared_mailboxes_data, dict):
|
|
289
|
+
shared_mailboxes_data = [shared_mailboxes_data]
|
|
290
|
+
for shared_mailbox in shared_mailboxes_data:
|
|
291
|
+
if shared_mailbox:
|
|
292
|
+
shared_mailboxes.append(
|
|
293
|
+
SharedMailbox(
|
|
294
|
+
name=shared_mailbox.get("DisplayName", ""),
|
|
295
|
+
user_principal_name=shared_mailbox.get(
|
|
296
|
+
"UserPrincipalName", ""
|
|
297
|
+
),
|
|
298
|
+
external_directory_object_id=shared_mailbox.get(
|
|
299
|
+
"ExternalDirectoryObjectId", ""
|
|
300
|
+
),
|
|
301
|
+
identity=shared_mailbox.get("Identity", ""),
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
except Exception as error:
|
|
305
|
+
logger.error(
|
|
306
|
+
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
|
307
|
+
)
|
|
308
|
+
return shared_mailboxes
|
|
309
|
+
|
|
251
310
|
|
|
252
311
|
class Organization(BaseModel):
|
|
253
312
|
name: str
|
|
@@ -342,6 +401,8 @@ class AuditDelegate(Enum):
|
|
|
342
401
|
|
|
343
402
|
|
|
344
403
|
class AuditOwner(Enum):
|
|
404
|
+
"""Audit actions for mailbox owner operations."""
|
|
405
|
+
|
|
345
406
|
APPLY_RECORD = "ApplyRecord"
|
|
346
407
|
CREATE = "Create"
|
|
347
408
|
HARD_DELETE = "HardDelete"
|
|
@@ -353,3 +414,20 @@ class AuditOwner(Enum):
|
|
|
353
414
|
UPDATE_CALENDAR_DELEGATION = "UpdateCalendarDelegation"
|
|
354
415
|
UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions"
|
|
355
416
|
UPDATE_INBOX_RULES = "UpdateInboxRules"
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class SharedMailbox(BaseModel):
|
|
420
|
+
"""
|
|
421
|
+
Model for Exchange Online shared mailbox.
|
|
422
|
+
|
|
423
|
+
Attributes:
|
|
424
|
+
name: Display name of the shared mailbox.
|
|
425
|
+
user_principal_name: User principal name (email) of the shared mailbox.
|
|
426
|
+
external_directory_object_id: The Entra ID object ID for cross-referencing.
|
|
427
|
+
identity: Identity of the shared mailbox in Exchange.
|
|
428
|
+
"""
|
|
429
|
+
|
|
430
|
+
name: str
|
|
431
|
+
user_principal_name: str
|
|
432
|
+
external_directory_object_id: str
|
|
433
|
+
identity: str
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Provider": "m365",
|
|
3
|
+
"CheckID": "exchange_shared_mailbox_sign_in_disabled",
|
|
4
|
+
"CheckTitle": "Shared mailbox has sign-in blocked",
|
|
5
|
+
"CheckType": [],
|
|
6
|
+
"ServiceName": "exchange",
|
|
7
|
+
"SubServiceName": "",
|
|
8
|
+
"ResourceIdTemplate": "",
|
|
9
|
+
"Severity": "medium",
|
|
10
|
+
"ResourceType": "Shared Mailbox",
|
|
11
|
+
"ResourceGroup": "IAM",
|
|
12
|
+
"Description": "Shared mailboxes are used for collaboration and should not permit direct sign-in. This check verifies that the **AccountEnabled** property is set to `false` in Entra ID for all shared mailboxes, preventing direct authentication.",
|
|
13
|
+
"Risk": "When sign-in is enabled on shared mailboxes, users with the password can bypass delegation controls and access the mailbox directly. This undermines **accountability** since actions cannot be attributed to individual users, and it increases the attack surface for credential-based attacks.",
|
|
14
|
+
"RelatedUrl": "",
|
|
15
|
+
"AdditionalURLs": [
|
|
16
|
+
"https://learn.microsoft.com/en-us/microsoft-365/admin/email/about-shared-mailboxes",
|
|
17
|
+
"https://learn.microsoft.com/en-us/microsoft-365/admin/email/create-a-shared-mailbox#block-sign-in-for-the-shared-mailbox-account"
|
|
18
|
+
],
|
|
19
|
+
"Remediation": {
|
|
20
|
+
"Code": {
|
|
21
|
+
"CLI": "Get-EXOMailbox -RecipientTypeDetails SharedMailbox | ForEach-Object { Update-MgUser -UserId $_.ExternalDirectoryObjectId -AccountEnabled:$false }",
|
|
22
|
+
"NativeIaC": "",
|
|
23
|
+
"Other": "1. Navigate to Entra admin center (https://entra.microsoft.com/)\n2. Expand Identity > Users and select All users\n3. Search for and select the shared mailbox user account\n4. In the properties pane, go to Account status\n5. Uncheck 'Account enabled' and click Save\n6. Repeat for all shared mailbox accounts",
|
|
24
|
+
"Terraform": ""
|
|
25
|
+
},
|
|
26
|
+
"Recommendation": {
|
|
27
|
+
"Text": "Block sign-in for all shared mailboxes to ensure users can only access them through delegation. This enforces accountability and reduces security risks from shared credentials.",
|
|
28
|
+
"Url": "https://hub.prowler.com/check/exchange_shared_mailbox_sign_in_disabled"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"Categories": [
|
|
32
|
+
"identity-access"
|
|
33
|
+
],
|
|
34
|
+
"DependsOn": [],
|
|
35
|
+
"RelatedTo": [],
|
|
36
|
+
"Notes": ""
|
|
37
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from prowler.lib.check.models import Check, CheckReportM365
|
|
4
|
+
from prowler.providers.m365.services.entra.entra_client import entra_client
|
|
5
|
+
from prowler.providers.m365.services.exchange.exchange_client import exchange_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class exchange_shared_mailbox_sign_in_disabled(Check):
|
|
9
|
+
"""
|
|
10
|
+
Verify that sign-in is blocked for all shared mailboxes.
|
|
11
|
+
|
|
12
|
+
Shared mailboxes are designed for collaboration and should not permit direct
|
|
13
|
+
sign-in. Users should access shared mailboxes through delegation only, which
|
|
14
|
+
ensures accountability and proper access controls.
|
|
15
|
+
|
|
16
|
+
- PASS: Shared mailbox has sign-in blocked (AccountEnabled = False in Entra ID).
|
|
17
|
+
- FAIL: Shared mailbox has sign-in enabled (AccountEnabled = True in Entra ID).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def execute(self) -> List[CheckReportM365]:
|
|
21
|
+
"""
|
|
22
|
+
Execute the check to verify shared mailbox sign-in status.
|
|
23
|
+
|
|
24
|
+
Cross-references shared mailboxes from Exchange Online with user accounts
|
|
25
|
+
in Entra ID to determine if sign-in is blocked.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
List[CheckReportM365]: A list of reports with the sign-in status for
|
|
29
|
+
each shared mailbox.
|
|
30
|
+
"""
|
|
31
|
+
findings = []
|
|
32
|
+
|
|
33
|
+
for shared_mailbox in exchange_client.shared_mailboxes:
|
|
34
|
+
report = CheckReportM365(
|
|
35
|
+
metadata=self.metadata(),
|
|
36
|
+
resource=shared_mailbox,
|
|
37
|
+
resource_name=shared_mailbox.name or shared_mailbox.user_principal_name,
|
|
38
|
+
resource_id=shared_mailbox.external_directory_object_id
|
|
39
|
+
or shared_mailbox.identity,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Look up the user in Entra ID by their external directory object ID
|
|
43
|
+
entra_user = entra_client.users.get(
|
|
44
|
+
shared_mailbox.external_directory_object_id
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if not entra_user:
|
|
48
|
+
report.status = "FAIL"
|
|
49
|
+
report.status_extended = f"Shared mailbox {shared_mailbox.user_principal_name} could not be found in Entra ID for verification."
|
|
50
|
+
elif entra_user.account_enabled:
|
|
51
|
+
report.status = "FAIL"
|
|
52
|
+
report.status_extended = f"Shared mailbox {shared_mailbox.user_principal_name} has sign-in enabled."
|
|
53
|
+
else:
|
|
54
|
+
report.status = "PASS"
|
|
55
|
+
report.status_extended = f"Shared mailbox {shared_mailbox.user_principal_name} has sign-in blocked."
|
|
56
|
+
|
|
57
|
+
findings.append(report)
|
|
58
|
+
|
|
59
|
+
return findings
|
|
File without changes
|
|
File without changes
|