prowler-cloud 5.17.1__py3-none-any.whl → 5.18.0__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.
Files changed (219) hide show
  1. dashboard/compliance/hipaa_azure.py +25 -0
  2. dashboard/pages/overview.py +20 -11
  3. prowler/AGENTS.md +1 -1
  4. prowler/CHANGELOG.md +43 -0
  5. prowler/__main__.py +5 -0
  6. prowler/compliance/azure/hipaa_azure.json +820 -0
  7. prowler/compliance/m365/cis_4.0_m365.json +6 -2
  8. prowler/compliance/m365/cis_6.0_m365.json +6 -2
  9. prowler/compliance/m365/iso27001_2022_m365.json +13 -11
  10. prowler/compliance/openstack/__init__.py +0 -0
  11. prowler/config/config.py +2 -1
  12. prowler/config/config.yaml +4 -1
  13. prowler/config/openstack_mutelist_example.yaml +60 -0
  14. prowler/lib/check/check.py +4 -0
  15. prowler/lib/check/models.py +27 -2
  16. prowler/lib/cli/parser.py +3 -2
  17. prowler/lib/outputs/finding.py +14 -0
  18. prowler/lib/outputs/html/html.py +72 -0
  19. prowler/lib/outputs/jira/jira.py +3 -3
  20. prowler/lib/outputs/outputs.py +2 -0
  21. prowler/lib/outputs/summary_table.py +7 -0
  22. prowler/lib/timeline/__init__.py +0 -0
  23. prowler/lib/timeline/models.py +27 -0
  24. prowler/lib/timeline/timeline.py +36 -0
  25. prowler/providers/aws/lib/cloudtrail_timeline/__init__.py +0 -0
  26. prowler/providers/aws/lib/cloudtrail_timeline/cloudtrail_timeline.py +218 -0
  27. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/__init__.py +0 -0
  28. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.metadata.json +40 -0
  29. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.py +58 -0
  30. prowler/providers/aws/services/codebuild/codebuild_service.py +45 -0
  31. prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.metadata.json +1 -1
  32. prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py +4 -0
  33. prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.metadata.json +1 -1
  34. prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.py +4 -0
  35. prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.metadata.json +1 -1
  36. prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.py +2 -0
  37. prowler/providers/aws/services/iam/lib/policy.py +19 -3
  38. prowler/providers/aws/services/rds/rds_instance_extended_support/__init__.py +0 -0
  39. prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.metadata.json +41 -0
  40. prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.py +37 -0
  41. prowler/providers/aws/services/rds/rds_service.py +4 -0
  42. prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json +1 -1
  43. prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.py +5 -1
  44. prowler/providers/azure/lib/service/service.py +23 -0
  45. prowler/providers/azure/services/app/app_client_certificates_on/app_client_certificates_on.metadata.json +18 -12
  46. prowler/providers/azure/services/app/app_ensure_auth_is_set_up/app_ensure_auth_is_set_up.metadata.json +18 -11
  47. prowler/providers/azure/services/app/app_ensure_http_is_redirected_to_https/app_ensure_http_is_redirected_to_https.metadata.json +19 -12
  48. prowler/providers/azure/services/app/app_ensure_java_version_is_latest/app_ensure_java_version_is_latest.metadata.json +19 -12
  49. prowler/providers/azure/services/app/app_ensure_php_version_is_latest/app_ensure_php_version_is_latest.metadata.json +19 -12
  50. prowler/providers/azure/services/app/app_ensure_python_version_is_latest/app_ensure_python_version_is_latest.metadata.json +19 -12
  51. prowler/providers/azure/services/app/app_ensure_using_http20/app_ensure_using_http20.metadata.json +18 -11
  52. prowler/providers/azure/services/app/app_ftp_deployment_disabled/app_ftp_deployment_disabled.metadata.json +21 -13
  53. prowler/providers/azure/services/app/app_function_access_keys_configured/app_function_access_keys_configured.metadata.json +19 -11
  54. prowler/providers/azure/services/app/app_function_application_insights_enabled/app_function_application_insights_enabled.metadata.json +21 -14
  55. prowler/providers/azure/services/app/app_function_ftps_deployment_disabled/app_function_ftps_deployment_disabled.metadata.json +18 -13
  56. prowler/providers/azure/services/app/app_function_identity_is_configured/app_function_identity_is_configured.metadata.json +20 -13
  57. prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.metadata.json +18 -11
  58. prowler/providers/azure/services/app/app_function_latest_runtime_version/app_function_latest_runtime_version.metadata.json +20 -13
  59. prowler/providers/azure/services/app/app_function_not_publicly_accessible/app_function_not_publicly_accessible.metadata.json +20 -13
  60. prowler/providers/azure/services/app/app_function_vnet_integration_enabled/app_function_vnet_integration_enabled.metadata.json +21 -14
  61. prowler/providers/azure/services/app/app_http_logs_enabled/app_http_logs_enabled.metadata.json +18 -12
  62. prowler/providers/azure/services/app/app_minimum_tls_version_12/app_minimum_tls_version_12.metadata.json +20 -12
  63. prowler/providers/azure/services/app/app_register_with_identity/app_register_with_identity.metadata.json +18 -11
  64. prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.metadata.json +18 -12
  65. prowler/providers/azure/services/containerregistry/containerregistry_admin_user_disabled/containerregistry_admin_user_disabled.metadata.json +17 -11
  66. prowler/providers/azure/services/containerregistry/containerregistry_not_publicly_accessible/containerregistry_not_publicly_accessible.metadata.json +18 -12
  67. prowler/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link.metadata.json +21 -13
  68. prowler/providers/azure/services/cosmosdb/cosmosdb_account_firewall_use_selected_networks/cosmosdb_account_firewall_use_selected_networks.metadata.json +20 -12
  69. prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/cosmosdb_account_use_aad_and_rbac.metadata.json +19 -13
  70. prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_private_endpoints/cosmosdb_account_use_private_endpoints.metadata.json +20 -13
  71. prowler/providers/azure/services/databricks/databricks_workspace_cmk_encryption_enabled/databricks_workspace_cmk_encryption_enabled.metadata.json +20 -14
  72. prowler/providers/azure/services/databricks/databricks_workspace_vnet_injection_enabled/databricks_workspace_vnet_injection_enabled.metadata.json +20 -14
  73. 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
  74. prowler/providers/azure/services/defender/defender_assessments_vm_endpoint_protection_installed/defender_assessments_vm_endpoint_protection_installed.metadata.json +17 -11
  75. prowler/providers/azure/services/defender/defender_attack_path_notifications_properly_configured/defender_attack_path_notifications_properly_configured.metadata.json +19 -13
  76. 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
  77. prowler/providers/azure/services/defender/defender_auto_provisioning_vulnerabilty_assessments_machines_on/defender_auto_provisioning_vulnerabilty_assessments_machines_on.metadata.json +19 -12
  78. prowler/providers/azure/services/defender/defender_container_images_resolved_vulnerabilities/defender_container_images_resolved_vulnerabilities.metadata.json +20 -12
  79. prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.metadata.json +22 -13
  80. 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
  81. prowler/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on.metadata.json +17 -11
  82. 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
  83. prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.metadata.json +17 -11
  84. prowler/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on.metadata.json +17 -11
  85. prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.metadata.json +17 -11
  86. prowler/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on.metadata.json +17 -11
  87. prowler/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on.metadata.json +17 -11
  88. 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
  89. prowler/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on.metadata.json +19 -11
  90. 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
  91. prowler/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on.metadata.json +17 -11
  92. prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.metadata.json +17 -11
  93. prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.metadata.json +20 -12
  94. prowler/providers/azure/services/defender/defender_ensure_notify_alerts_severity_is_high/defender_ensure_notify_alerts_severity_is_high.metadata.json +19 -12
  95. prowler/providers/azure/services/defender/defender_ensure_notify_emails_to_owners/defender_ensure_notify_emails_to_owners.metadata.json +19 -12
  96. prowler/providers/azure/services/defender/defender_ensure_system_updates_are_applied/defender_ensure_system_updates_are_applied.metadata.json +17 -9
  97. prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.metadata.json +21 -13
  98. prowler/providers/azure/services/entra/entra_service.py +3 -11
  99. prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py +6 -0
  100. 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
  101. prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json +16 -10
  102. prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.metadata.json +18 -12
  103. prowler/providers/azure/services/keyvault/keyvault_rbac_secret_expiration_set/keyvault_rbac_secret_expiration_set.py +10 -11
  104. prowler/providers/azure/services/keyvault/keyvault_service.py +164 -81
  105. prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_connection_activated/mysql_flexible_server_audit_log_connection_activated.metadata.json +18 -12
  106. prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_enabled/mysql_flexible_server_audit_log_enabled.metadata.json +19 -12
  107. prowler/providers/azure/services/mysql/mysql_flexible_server_minimum_tls_version_12/mysql_flexible_server_minimum_tls_version_12.metadata.json +18 -12
  108. prowler/providers/azure/services/mysql/mysql_flexible_server_ssl_connection_enabled/mysql_flexible_server_ssl_connection_enabled.metadata.json +19 -12
  109. prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.metadata.json +21 -12
  110. prowler/providers/azure/services/network/network_flow_log_captured_sent/network_flow_log_captured_sent.metadata.json +19 -12
  111. prowler/providers/azure/services/network/network_flow_log_more_than_90_days/network_flow_log_more_than_90_days.metadata.json +21 -12
  112. prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.metadata.json +18 -12
  113. prowler/providers/azure/services/network/network_public_ip_shodan/network_public_ip_shodan.metadata.json +15 -10
  114. prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.metadata.json +20 -12
  115. prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.metadata.json +19 -12
  116. prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.metadata.json +19 -12
  117. prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.metadata.json +21 -13
  118. prowler/providers/azure/services/policy/policy_ensure_asc_enforcement_enabled/policy_ensure_asc_enforcement_enabled.metadata.json +16 -11
  119. prowler/providers/azure/services/postgresql/postgresql_flexible_server_allow_access_services_disabled/postgresql_flexible_server_allow_access_services_disabled.metadata.json +20 -13
  120. prowler/providers/azure/services/postgresql/postgresql_flexible_server_connection_throttling_on/postgresql_flexible_server_connection_throttling_on.metadata.json +18 -12
  121. prowler/providers/azure/services/postgresql/postgresql_flexible_server_enforce_ssl_enabled/postgresql_flexible_server_enforce_ssl_enabled.metadata.json +19 -13
  122. prowler/providers/azure/services/postgresql/postgresql_flexible_server_entra_id_authentication_enabled/postgresql_flexible_server_entra_id_authentication_enabled.metadata.json +4 -4
  123. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_checkpoints_on/postgresql_flexible_server_log_checkpoints_on.metadata.json +19 -13
  124. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_connections_on/postgresql_flexible_server_log_connections_on.metadata.json +18 -11
  125. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_disconnections_on/postgresql_flexible_server_log_disconnections_on.metadata.json +18 -12
  126. 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
  127. prowler/providers/azure/services/sqlserver/sqlserver_auditing_enabled/sqlserver_auditing_enabled.metadata.json +20 -13
  128. prowler/providers/azure/services/sqlserver/sqlserver_auditing_retention_90_days/sqlserver_auditing_retention_90_days.metadata.json +20 -12
  129. prowler/providers/azure/services/sqlserver/sqlserver_azuread_administrator_enabled/sqlserver_azuread_administrator_enabled.metadata.json +18 -12
  130. prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json +23 -13
  131. prowler/providers/azure/services/sqlserver/sqlserver_recommended_minimal_tls_version/sqlserver_recommended_minimal_tls_version.metadata.json +19 -12
  132. prowler/providers/azure/services/sqlserver/sqlserver_tde_encrypted_with_cmk/sqlserver_tde_encrypted_with_cmk.metadata.json +20 -13
  133. prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json +20 -13
  134. prowler/providers/azure/services/sqlserver/sqlserver_unrestricted_inbound_access/sqlserver_unrestricted_inbound_access.metadata.json +18 -12
  135. prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json +19 -12
  136. prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json +19 -12
  137. prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json +18 -12
  138. prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled/sqlserver_vulnerability_assessment_enabled.metadata.json +19 -12
  139. prowler/providers/azure/services/storage/storage_account_key_access_disabled/storage_account_key_access_disabled.metadata.json +17 -12
  140. prowler/providers/azure/services/storage/storage_blob_public_access_level_is_disabled/storage_blob_public_access_level_is_disabled.metadata.json +18 -12
  141. prowler/providers/azure/services/storage/storage_blob_versioning_is_enabled/storage_blob_versioning_is_enabled.metadata.json +19 -11
  142. prowler/providers/azure/services/storage/storage_cross_tenant_replication_disabled/storage_cross_tenant_replication_disabled.metadata.json +19 -13
  143. prowler/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied.metadata.json +19 -12
  144. prowler/providers/azure/services/storage/storage_default_to_entra_authorization_enabled/storage_default_to_entra_authorization_enabled.metadata.json +20 -13
  145. 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
  146. prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys/storage_ensure_encryption_with_customer_managed_keys.metadata.json +15 -10
  147. 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
  148. prowler/providers/azure/services/storage/storage_ensure_minimum_tls_version_12/storage_ensure_minimum_tls_version_12.metadata.json +14 -10
  149. prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts.metadata.json +19 -11
  150. prowler/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled.metadata.json +17 -12
  151. prowler/providers/azure/services/storage/storage_geo_redundant_enabled/storage_geo_redundant_enabled.metadata.json +19 -12
  152. prowler/providers/azure/services/storage/storage_infrastructure_encryption_is_enabled/storage_infrastructure_encryption_is_enabled.metadata.json +13 -9
  153. prowler/providers/azure/services/storage/storage_key_rotation_90_days/storage_key_rotation_90_days.metadata.json +17 -12
  154. prowler/providers/azure/services/storage/storage_secure_transfer_required_is_enabled/storage_secure_transfer_required_is_enabled.metadata.json +15 -11
  155. prowler/providers/azure/services/storage/storage_smb_channel_encryption_with_secure_algorithm/storage_smb_channel_encryption_with_secure_algorithm.metadata.json +19 -12
  156. prowler/providers/azure/services/storage/storage_smb_protocol_version_is_latest/storage_smb_protocol_version_is_latest.metadata.json +19 -13
  157. prowler/providers/cloudflare/cloudflare_provider.py +95 -12
  158. prowler/providers/cloudflare/lib/arguments/arguments.py +7 -0
  159. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/__init__.py +0 -0
  160. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.metadata.json +36 -0
  161. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.py +109 -0
  162. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/__init__.py +0 -0
  163. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.metadata.json +36 -0
  164. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.py +73 -0
  165. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/__init__.py +0 -0
  166. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.metadata.json +36 -0
  167. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.py +60 -0
  168. prowler/providers/cloudflare/services/dns/dns_record_proxied/__init__.py +0 -0
  169. prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.metadata.json +36 -0
  170. prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.py +49 -0
  171. prowler/providers/cloudflare/services/dns/dns_service.py +52 -6
  172. prowler/providers/cloudflare/services/firewall/__init__.py +0 -0
  173. prowler/providers/cloudflare/services/firewall/firewall_client.py +4 -0
  174. prowler/providers/cloudflare/services/firewall/firewall_service.py +123 -0
  175. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/__init__.py +0 -0
  176. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.metadata.json +36 -0
  177. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.py +53 -0
  178. prowler/providers/cloudflare/services/zone/zone_service.py +133 -1
  179. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/__init__.py +0 -0
  180. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.metadata.json +36 -0
  181. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.py +58 -0
  182. prowler/providers/common/provider.py +23 -0
  183. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/__init__.py +0 -0
  184. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.metadata.json +37 -0
  185. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.py +35 -0
  186. prowler/providers/gcp/services/compute/compute_service.py +2 -0
  187. prowler/providers/m365/lib/powershell/m365_powershell.py +47 -1
  188. prowler/providers/m365/services/defender/defender_service.py +52 -0
  189. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/__init__.py +0 -0
  190. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.metadata.json +38 -0
  191. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.py +53 -0
  192. prowler/providers/m365/services/exchange/exchange_service.py +78 -0
  193. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/__init__.py +0 -0
  194. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.metadata.json +37 -0
  195. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.py +59 -0
  196. prowler/providers/openstack/__init__.py +0 -0
  197. prowler/providers/openstack/exceptions/__init__.py +0 -0
  198. prowler/providers/openstack/exceptions/exceptions.py +166 -0
  199. prowler/providers/openstack/lib/__init__.py +0 -0
  200. prowler/providers/openstack/lib/arguments/__init__.py +0 -0
  201. prowler/providers/openstack/lib/arguments/arguments.py +113 -0
  202. prowler/providers/openstack/lib/mutelist/__init__.py +0 -0
  203. prowler/providers/openstack/lib/mutelist/mutelist.py +31 -0
  204. prowler/providers/openstack/lib/service/__init__.py +0 -0
  205. prowler/providers/openstack/lib/service/service.py +21 -0
  206. prowler/providers/openstack/models.py +100 -0
  207. prowler/providers/openstack/openstack_provider.py +515 -0
  208. prowler/providers/openstack/services/__init__.py +0 -0
  209. prowler/providers/openstack/services/compute/__init__.py +0 -0
  210. prowler/providers/openstack/services/compute/compute_client.py +4 -0
  211. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/__init__.py +0 -0
  212. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.metadata.json +40 -0
  213. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.py +35 -0
  214. prowler/providers/openstack/services/compute/compute_service.py +63 -0
  215. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.0.dist-info}/METADATA +11 -9
  216. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.0.dist-info}/RECORD +219 -155
  217. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.0.dist-info}/LICENSE +0 -0
  218. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.0.dist-info}/WHEEL +0 -0
  219. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,218 @@
1
+ """CloudTrail timeline service for AWS.
2
+
3
+ Queries AWS CloudTrail to retrieve timeline events for resources,
4
+ showing who performed actions and when.
5
+ """
6
+
7
+ import json
8
+ from datetime import datetime, timedelta, timezone
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from botocore.exceptions import ClientError
12
+
13
+ from prowler.lib.logger import logger
14
+ from prowler.lib.timeline.models import TimelineEvent
15
+ from prowler.lib.timeline.timeline import TimelineService
16
+
17
+
18
+ class CloudTrailTimeline(TimelineService):
19
+ """AWS CloudTrail implementation of TimelineService.
20
+
21
+ Args:
22
+ session: boto3.Session for AWS API calls
23
+ lookback_days: Number of days to look back (default 90, max 90 for Event History)
24
+ max_results: Maximum number of events to return
25
+ write_events_only: If True, filter out read-only events (Describe*, Get*, List*, etc.)
26
+ """
27
+
28
+ MAX_LOOKBACK_DAYS = 90
29
+
30
+ DEFAULT_MAX_RESULTS = 50 # Default page size for CloudTrail queries
31
+
32
+ # Prefixes for read-only API operations that don't modify resources
33
+ READ_ONLY_PREFIXES = (
34
+ "Describe",
35
+ "Get",
36
+ "List",
37
+ "Head",
38
+ "Check",
39
+ "Lookup",
40
+ "Search",
41
+ "Scan",
42
+ "Query",
43
+ "BatchGet",
44
+ "Select",
45
+ )
46
+
47
+ def __init__(
48
+ self,
49
+ session,
50
+ lookback_days: int = 90,
51
+ max_results: Optional[int] = None,
52
+ write_events_only: bool = True,
53
+ ):
54
+ self._session = session
55
+ self._lookback_days = min(lookback_days, self.MAX_LOOKBACK_DAYS)
56
+ self._max_results = max_results or self.DEFAULT_MAX_RESULTS
57
+ self._write_events_only = write_events_only
58
+ self._clients: Dict[str, Any] = {}
59
+
60
+ DEFAULT_REGION = "us-east-1" # Default for global resources in commercial partition
61
+
62
+ def get_resource_timeline(
63
+ self,
64
+ region: Optional[str] = None,
65
+ resource_id: Optional[str] = None,
66
+ resource_uid: Optional[str] = None,
67
+ ) -> List[Dict[str, Any]]:
68
+ """Get CloudTrail timeline events for a resource.
69
+
70
+ Args:
71
+ region: AWS region to query. Defaults to us-east-1 for global resources
72
+ (IAM, S3, Route53, etc.) in the commercial partition. Caller
73
+ should provide the correct region for regional resources.
74
+ resource_id: AWS resource ID (e.g., sg-1234567890abcdef0)
75
+ resource_uid: AWS resource ARN (unique identifier)
76
+
77
+ Returns:
78
+ List of timeline event dictionaries
79
+
80
+ Raises:
81
+ ValueError: If neither resource_id nor resource_uid is provided
82
+ ClientError: If AWS API call fails
83
+ """
84
+ resource_identifier = resource_uid or resource_id
85
+ if not resource_identifier:
86
+ raise ValueError("Either resource_id or resource_uid must be provided")
87
+
88
+ region = region or self.DEFAULT_REGION
89
+
90
+ try:
91
+ raw_events = self._lookup_events(resource_identifier, region)
92
+
93
+ events = []
94
+ for raw_event in raw_events:
95
+ # Filter read-only events if write_events_only is enabled
96
+ if self._write_events_only:
97
+ event_name = raw_event.get("EventName", "")
98
+ if self._is_read_only_event(event_name):
99
+ continue
100
+
101
+ parsed = self._parse_event(raw_event)
102
+ if parsed:
103
+ events.append(parsed)
104
+
105
+ return events
106
+
107
+ except ClientError as e:
108
+ logger.error(
109
+ f"CloudTrail timeline error for {resource_identifier} in {region}: "
110
+ f"{e.response['Error']['Code']} - {e.response['Error']['Message']}"
111
+ )
112
+ raise
113
+ except Exception as e:
114
+ lineno = e.__traceback__.tb_lineno if e.__traceback__ else "?"
115
+ logger.error(
116
+ f"CloudTrail timeline unexpected error: "
117
+ f"{e.__class__.__name__}[{lineno}]: {e}"
118
+ )
119
+ return []
120
+
121
+ def _is_read_only_event(self, event_name: str) -> bool:
122
+ """Check if an event is a read-only operation."""
123
+ return event_name.startswith(self.READ_ONLY_PREFIXES)
124
+
125
+ def _get_client(self, region: str):
126
+ """Get or create a CloudTrail client for the specified region."""
127
+ if region not in self._clients:
128
+ self._clients[region] = self._session.client(
129
+ "cloudtrail", region_name=region
130
+ )
131
+ return self._clients[region]
132
+
133
+ def _lookup_events(
134
+ self, resource_identifier: str, region: str
135
+ ) -> List[Dict[str, Any]]:
136
+ """Query CloudTrail for events related to a specific resource.
137
+
138
+ Uses MaxResults to limit the number of events returned, preparing
139
+ for API-level pagination. Currently returns up to max_results events
140
+ from the first page only.
141
+ """
142
+ client = self._get_client(region)
143
+ start_time = datetime.now(timezone.utc) - timedelta(days=self._lookback_days)
144
+
145
+ # Use direct API call with MaxResults instead of paginator
146
+ # This limits CloudTrail to return only max_results events
147
+ response = client.lookup_events(
148
+ LookupAttributes=[
149
+ {"AttributeKey": "ResourceName", "AttributeValue": resource_identifier}
150
+ ],
151
+ StartTime=start_time,
152
+ MaxResults=self._max_results,
153
+ )
154
+
155
+ return response.get("Events", [])
156
+
157
+ def _parse_event(self, raw_event: Dict[str, Any]) -> Optional[Dict[str, Any]]:
158
+ """Parse a raw CloudTrail event into a TimelineEvent dictionary."""
159
+ try:
160
+ cloud_trail_event = raw_event.get("CloudTrailEvent", "{}")
161
+ if isinstance(cloud_trail_event, str):
162
+ details = json.loads(cloud_trail_event)
163
+ else:
164
+ details = cloud_trail_event
165
+
166
+ user_identity = details.get("userIdentity", {})
167
+
168
+ event = TimelineEvent(
169
+ event_id=raw_event.get("EventId"),
170
+ event_time=raw_event["EventTime"],
171
+ event_name=raw_event.get("EventName", "Unknown"),
172
+ event_source=raw_event.get("EventSource", "Unknown"),
173
+ actor=self._extract_actor(user_identity),
174
+ actor_uid=user_identity.get("arn"),
175
+ actor_type=user_identity.get("type"),
176
+ source_ip_address=details.get("sourceIPAddress"),
177
+ user_agent=details.get("userAgent"),
178
+ request_data=details.get("requestParameters"),
179
+ response_data=details.get("responseElements"),
180
+ error_code=details.get("errorCode"),
181
+ error_message=details.get("errorMessage"),
182
+ )
183
+
184
+ return event.dict()
185
+
186
+ except Exception as e:
187
+ logger.warning(
188
+ f"CloudTrail timeline: failed to parse event: "
189
+ f"{e.__class__.__name__}: {e}"
190
+ )
191
+ return None
192
+
193
+ @staticmethod
194
+ def _extract_actor(user_identity: Dict[str, Any]) -> str:
195
+ """Extract a human-readable actor name from CloudTrail userIdentity."""
196
+ # Try ARN first - most reliable
197
+ if arn := user_identity.get("arn"):
198
+ if "/" in arn:
199
+ parts = arn.split("/")
200
+ # For assumed-role, return the role name (second-to-last part)
201
+ if "assumed-role" in arn and len(parts) >= 2:
202
+ return parts[-2]
203
+ return parts[-1]
204
+ return arn.split(":")[-1]
205
+
206
+ # Fall back to userName
207
+ if username := user_identity.get("userName"):
208
+ return username
209
+
210
+ # Fall back to principalId
211
+ if principal_id := user_identity.get("principalId"):
212
+ return principal_id
213
+
214
+ # For service-invoked actions
215
+ if invoking_service := user_identity.get("invokedBy"):
216
+ return invoking_service
217
+
218
+ return "Unknown"
@@ -0,0 +1,40 @@
1
+ {
2
+ "Provider": "aws",
3
+ "CheckID": "codebuild_project_webhook_filters_use_anchored_patterns",
4
+ "CheckTitle": "CodeBuild project webhook filters use anchored regex patterns",
5
+ "CheckType": [
6
+ "Software and Configuration Checks/AWS Security Best Practices"
7
+ ],
8
+ "ServiceName": "codebuild",
9
+ "SubServiceName": "",
10
+ "ResourceIdTemplate": "",
11
+ "Severity": "high",
12
+ "ResourceType": "AwsCodeBuildProject",
13
+ "ResourceGroup": "devops",
14
+ "Description": "AWS CodeBuild webhook filters using `ACTOR_ACCOUNT_ID`, `HEAD_REF`, or `BASE_REF` have regex patterns anchored with `^` (start) and `$` (end) to enforce exact matching and prevent substring bypass attacks.",
15
+ "Risk": "Unanchored patterns expose CI/CD pipelines to **CodeBreach** attacks. Attackers can bypass `ACTOR_ACCOUNT_ID` filters by creating GitHub accounts with IDs containing trusted values as substrings. **Confidentiality**: Credentials leaked via build logs. **Integrity**: Malicious code injected into builds. **Availability**: Resource exhaustion through unauthorized builds.",
16
+ "RelatedUrl": "",
17
+ "Remediation": {
18
+ "Code": {
19
+ "CLI": "aws codebuild update-webhook --project-name <PROJECT_NAME> --filter-groups '[[{\"type\":\"ACTOR_ACCOUNT_ID\",\"pattern\":\"^123456$|^234567$\"}]]'",
20
+ "NativeIaC": "AWSTemplateFormatVersion: '2010-09-09'\nResources:\n CodeBuildWebhook:\n Type: AWS::CodeBuild::Project\n Properties:\n Triggers:\n Webhook: true\n FilterGroups:\n - - Type: ACTOR_ACCOUNT_ID\n Pattern: '^123456$|^234567$' # Anchored pattern",
21
+ "Other": "1. Open AWS Console and navigate to CodeBuild. 2. Select the project with webhook filters. 3. Click Edit and go to Primary source webhook events. 4. For each filter using ACTOR_ACCOUNT_ID, HEAD_REF, or BASE_REF, update patterns to include ^ at start and $ at end (e.g., change '123456|234567' to '^123456$|^234567$'). 5. Save changes.",
22
+ "Terraform": "resource \"aws_codebuild_webhook\" \"example\" {\n project_name = aws_codebuild_project.example.name\n filter_group {\n filter {\n type = \"ACTOR_ACCOUNT_ID\"\n pattern = \"^123456$|^234567$\" # Anchored pattern\n }\n }\n}"
23
+ },
24
+ "Recommendation": {
25
+ "Text": "Anchor all webhook filter patterns with `^` (start) and `$` (end) to enforce exact matching. For multiple values use: `^value1$|^value2$`. This prevents attackers from bypassing filters using substring matches.",
26
+ "Url": "https://hub.prowler.com/check/codebuild_project_webhook_filters_use_anchored_patterns"
27
+ }
28
+ },
29
+ "Categories": [
30
+ "software-supply-chain",
31
+ "ci-cd"
32
+ ],
33
+ "DependsOn": [],
34
+ "RelatedTo": [],
35
+ "Notes": "This check targets the CodeBreach vulnerability disclosed by Wiz Research. The vulnerability allows attackers to bypass ACTOR_ACCOUNT_ID filters by creating GitHub accounts with IDs that contain trusted IDs as substrings.",
36
+ "AdditionalURLs": [
37
+ "https://www.wiz.io/blog/wiz-research-codebreach-vulnerability-aws-codebuild",
38
+ "https://docs.aws.amazon.com/codebuild/latest/userguide/github-webhook.html"
39
+ ]
40
+ }
@@ -0,0 +1,58 @@
1
+ from typing import List
2
+
3
+ from prowler.lib.check.models import Check, Check_Report_AWS
4
+ from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_client
5
+
6
+ HIGH_RISK_FILTER_TYPES = {"ACTOR_ACCOUNT_ID", "HEAD_REF", "BASE_REF"}
7
+
8
+
9
+ def is_pattern_anchored(pattern: str) -> bool:
10
+ """Check if each alternative in a pipe-separated pattern is anchored with ^ and $."""
11
+ if not pattern:
12
+ return True
13
+
14
+ for alt in pattern.split("|"):
15
+ alt = alt.strip()
16
+ if alt and not (alt.startswith("^") and alt.endswith("$")):
17
+ return False
18
+ return True
19
+
20
+
21
+ class codebuild_project_webhook_filters_use_anchored_patterns(Check):
22
+ def execute(self) -> List[Check_Report_AWS]:
23
+ findings = []
24
+
25
+ for project in codebuild_client.projects.values():
26
+ report = Check_Report_AWS(metadata=self.metadata(), resource=project)
27
+ report.status = "PASS"
28
+ report.status_extended = (
29
+ f"CodeBuild project {project.name} has no webhook configured or all "
30
+ "webhook filter patterns are properly anchored."
31
+ )
32
+
33
+ if not project.webhook or not project.webhook.filter_groups:
34
+ findings.append(report)
35
+ continue
36
+
37
+ unanchored_filters = []
38
+ for filter_group in project.webhook.filter_groups:
39
+ for webhook_filter in filter_group.filters:
40
+ if webhook_filter.type in HIGH_RISK_FILTER_TYPES:
41
+ if not is_pattern_anchored(webhook_filter.pattern):
42
+ unanchored_filters.append(
43
+ f"{webhook_filter.type}: '{webhook_filter.pattern}'"
44
+ )
45
+
46
+ if unanchored_filters:
47
+ report.status = "FAIL"
48
+ filters_str = ", ".join(unanchored_filters[:3])
49
+ if len(unanchored_filters) > 3:
50
+ filters_str += f" and {len(unanchored_filters) - 3} more"
51
+ report.status_extended = (
52
+ f"CodeBuild project {project.name} has webhook filters with "
53
+ f"unanchored patterns that could allow bypass attacks: {filters_str}."
54
+ )
55
+
56
+ findings.append(report)
57
+
58
+ return findings
@@ -122,6 +122,29 @@ class Codebuild(AWSService):
122
122
  project.tags = project_info.get("tags", [])
123
123
  project.service_role_arn = project_info.get("serviceRole", "")
124
124
  project.project_visibility = project_info.get("projectVisibility", "")
125
+
126
+ # Extract webhook configuration
127
+ webhook_data = project_info.get("webhook")
128
+ if webhook_data:
129
+ filter_groups = []
130
+ for fg in webhook_data.get("filterGroups", []):
131
+ filters = []
132
+ for f in fg:
133
+ filters.append(
134
+ WebhookFilter(
135
+ type=f.get("type", ""),
136
+ pattern=f.get("pattern", ""),
137
+ exclude_matched_pattern=f.get(
138
+ "excludeMatchedPattern", False
139
+ ),
140
+ )
141
+ )
142
+ filter_groups.append(WebhookFilterGroup(filters=filters))
143
+
144
+ project.webhook = Webhook(
145
+ filter_groups=filter_groups,
146
+ branch_filter=webhook_data.get("branchFilter"),
147
+ )
125
148
  except Exception as error:
126
149
  logger.error(
127
150
  f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
@@ -209,6 +232,27 @@ class CloudWatchLogs(BaseModel):
209
232
  stream_name: str
210
233
 
211
234
 
235
+ class WebhookFilter(BaseModel):
236
+ """Represents a single filter in a webhook filter group."""
237
+
238
+ type: str # ACTOR_ACCOUNT_ID, HEAD_REF, BASE_REF, EVENT, etc.
239
+ pattern: str
240
+ exclude_matched_pattern: bool = False
241
+
242
+
243
+ class WebhookFilterGroup(BaseModel):
244
+ """Represents a group of filters (AND logic within group)."""
245
+
246
+ filters: List[WebhookFilter] = []
247
+
248
+
249
+ class Webhook(BaseModel):
250
+ """Represents the webhook configuration for a CodeBuild project."""
251
+
252
+ filter_groups: List[WebhookFilterGroup] = []
253
+ branch_filter: Optional[str] = None
254
+
255
+
212
256
  class Project(BaseModel):
213
257
  name: str
214
258
  arn: str
@@ -224,6 +268,7 @@ class Project(BaseModel):
224
268
  cloudwatch_logs: Optional[CloudWatchLogs]
225
269
  tags: Optional[list]
226
270
  project_visibility: Optional[str] = None
271
+ webhook: Optional[Webhook] = None
227
272
 
228
273
 
229
274
  class ExportConfig(BaseModel):
@@ -38,5 +38,5 @@
38
38
  ],
39
39
  "DependsOn": [],
40
40
  "RelatedTo": [],
41
- "Notes": ""
41
+ "Notes": "This check supports the `trusted_account_ids` configuration in config.yaml to allow specific cross-account access without triggering a finding."
42
42
  }
@@ -6,6 +6,9 @@ from prowler.providers.aws.services.iam.lib.policy import is_policy_public
6
6
  class dynamodb_table_cross_account_access(Check):
7
7
  def execute(self):
8
8
  findings = []
9
+ trusted_account_ids = dynamodb_client.audit_config.get(
10
+ "trusted_account_ids", []
11
+ )
9
12
  for table in dynamodb_client.tables.values():
10
13
  if table.policy is None:
11
14
  continue
@@ -20,6 +23,7 @@ class dynamodb_table_cross_account_access(Check):
20
23
  table.policy,
21
24
  dynamodb_client.audited_account,
22
25
  is_cross_account_allowed=False,
26
+ trusted_account_ids=trusted_account_ids,
23
27
  ):
24
28
  report.status = "FAIL"
25
29
  report.status_extended = f"DynamoDB table {table.name} has a resource-based policy allowing cross account access."
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "DependsOn": [],
42
42
  "RelatedTo": [],
43
- "Notes": ""
43
+ "Notes": "This check supports the `trusted_account_ids` configuration in config.yaml to allow specific cross-account access without triggering a finding."
44
44
  }
@@ -8,6 +8,9 @@ from prowler.providers.aws.services.iam.lib.policy import is_policy_public
8
8
  class eventbridge_bus_cross_account_access(Check):
9
9
  def execute(self):
10
10
  findings = []
11
+ trusted_account_ids = eventbridge_client.audit_config.get(
12
+ "trusted_account_ids", []
13
+ )
11
14
  for bus in eventbridge_client.buses.values():
12
15
  if bus.policy is None:
13
16
  continue
@@ -20,6 +23,7 @@ class eventbridge_bus_cross_account_access(Check):
20
23
  bus.policy,
21
24
  eventbridge_client.audited_account,
22
25
  is_cross_account_allowed=False,
26
+ trusted_account_ids=trusted_account_ids,
23
27
  ):
24
28
  report.status = "FAIL"
25
29
  report.status_extended = (
@@ -39,5 +39,5 @@
39
39
  ],
40
40
  "DependsOn": [],
41
41
  "RelatedTo": [],
42
- "Notes": ""
42
+ "Notes": "This check supports the `trusted_account_ids` configuration in config.yaml to allow specific cross-account access without triggering a finding."
43
43
  }
@@ -6,6 +6,7 @@ from prowler.providers.aws.services.iam.lib.policy import is_policy_public
6
6
  class eventbridge_schema_registry_cross_account_access(Check):
7
7
  def execute(self):
8
8
  findings = []
9
+ trusted_account_ids = schema_client.audit_config.get("trusted_account_ids", [])
9
10
  for registry in schema_client.registries.values():
10
11
  if registry.policy is None:
11
12
  continue
@@ -16,6 +17,7 @@ class eventbridge_schema_registry_cross_account_access(Check):
16
17
  registry.policy,
17
18
  schema_client.audited_account,
18
19
  is_cross_account_allowed=False,
20
+ trusted_account_ids=trusted_account_ids,
19
21
  ):
20
22
  report.status = "FAIL"
21
23
  report.status_extended = f"EventBridge schema registry {registry.name} allows cross-account access."
@@ -387,6 +387,7 @@ def is_policy_public(
387
387
  is_cross_account_allowed=True,
388
388
  not_allowed_actions: list = [],
389
389
  check_cross_service_confused_deputy=False,
390
+ trusted_account_ids: list = None,
390
391
  ) -> bool:
391
392
  """
392
393
  Check if the policy allows public access to the resource.
@@ -397,10 +398,19 @@ def is_policy_public(
397
398
  is_cross_account_allowed (bool): If the policy can allow cross-account access, default: True (https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html#cross-service-confused-deputy-prevention)
398
399
  not_allowed_actions (list): List of actions that are not allowed, default: []. If not_allowed_actions is empty, the function will not consider the actions in the policy.
399
400
  check_cross_service_confused_deputy (bool): If the policy is checked for cross-service confused deputy, default: False
401
+ trusted_account_ids (list): A list of trusted accound ids to reduce false positives on cross-account checks
400
402
  Returns:
401
403
  bool: True if the policy allows public access, False otherwise
402
404
  """
403
405
  is_public = False
406
+
407
+ if trusted_account_ids is None:
408
+ trusted_account_ids = []
409
+
410
+ trusted_accounts = set(trusted_account_ids)
411
+ if source_account:
412
+ trusted_accounts.add(source_account)
413
+
404
414
  if policy:
405
415
  for statement in policy.get("Statement", []):
406
416
  # Only check allow statements
@@ -414,13 +424,19 @@ def is_policy_public(
414
424
  isinstance(principal.get("AWS"), str)
415
425
  and source_account
416
426
  and not is_cross_account_allowed
417
- and source_account not in principal.get("AWS", "")
427
+ and not any(
428
+ trusted_account in principal.get("AWS", "")
429
+ for trusted_account in trusted_accounts
430
+ )
418
431
  ) or (
419
432
  isinstance(principal.get("AWS"), list)
420
433
  and source_account
421
434
  and not is_cross_account_allowed
422
- and not any(
423
- source_account in principal_aws
435
+ and not all(
436
+ any(
437
+ trusted_account in principal_aws
438
+ for trusted_account in trusted_accounts
439
+ )
424
440
  for principal_aws in principal["AWS"]
425
441
  )
426
442
  ):
@@ -0,0 +1,41 @@
1
+ {
2
+ "Provider": "aws",
3
+ "CheckID": "rds_instance_extended_support",
4
+ "CheckTitle": "RDS instance is not enrolled in RDS Extended Support",
5
+ "CheckType": [
6
+ "Software and Configuration Checks/Patch Management",
7
+ "Software and Configuration Checks/AWS Security Best Practices"
8
+ ],
9
+ "ServiceName": "rds",
10
+ "SubServiceName": "",
11
+ "ResourceIdTemplate": "",
12
+ "Severity": "medium",
13
+ "ResourceType": "AwsRdsDbInstance",
14
+ "ResourceGroup": "database",
15
+ "Description": "**RDS DB instances** are evaluated for enrollment in Amazon RDS Extended Support. The check fails if `EngineLifecycleSupportis` set to `open-source-rds-extended-support`, indicating the instance will incur additional charges after standard support ends.",
16
+ "Risk": "DB instances enrolled in RDS Extended Support can incur additional charges after the end of standard support for the running database major version. Remaining on older major versions can also delay necessary upgrades, increasing operational and security risk.",
17
+ "RelatedUrl": "",
18
+ "AdditionalURLs": [
19
+ "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/extended-support-viewing.html",
20
+ "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/extended-support-charges.html",
21
+ "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/extended-support-creating-db-instance.html"
22
+ ],
23
+ "Remediation": {
24
+ "Code": {
25
+ "CLI": "aws rds modify-db-instance --db-instance-identifier <DB_INSTANCE_IDENTIFIER> --engine-version <TARGET_ENGINE_VERSION> --allow-major-version-upgrade --apply-immediately\n# For new DB instances created via automation, prevent enrollment by setting the lifecycle option:\naws rds create-db-instance ... --engine-lifecycle-support open-source-rds-extended-support-disabled",
26
+ "NativeIaC": "```yaml\n# CloudFormation: upgrade RDS engine version for an existing instance\nResources:\n <example_resource_name>:\n Type: AWS::RDS::DBInstance\n Properties:\n DBInstanceIdentifier: <example_resource_id>\n Engine: <engine>\n DBInstanceClass: db.t3.micro\n EngineVersion: <SUPPORTED_ENGINE_VERSION> # CRITICAL: move to a supported engine version\n AllowMajorVersionUpgrade: true # CRITICAL: required if upgrading major version\n ApplyImmediately: true # CRITICAL: apply change now to pass the check\n```",
27
+ "Other": "If your automation (CloudFormation/Terraform/SDK) creates or restores DB instances, set EngineLifecycleSupport/LifeCycleSupport to open-source-rds-extended-support-disabled where supported, and ensure your upgrade process keeps engines within standard support.",
28
+ "Terraform": "```hcl\n# Upgrade RDS engine version\nresource \"aws_db_instance\" \"<example_resource_name>\" {\n identifier = \"<example_resource_id>\"\n engine = \"<engine>\"\n instance_class = \"db.t3.micro\"\n allocated_storage = 20\n\n engine_version = \"<SUPPORTED_ENGINE_VERSION>\" # CRITICAL: use a supported version\n allow_major_version_upgrade = true # CRITICAL: needed for major upgrades\n apply_immediately = true # CRITICAL: apply now to pass the check\n}\n```"
29
+ },
30
+ "Recommendation": {
31
+ "Text": "Upgrade enrolled DB instances to an engine version covered under standard support to stop Extended Support charges. For new DB instances and restores created via automation, explicitly set the engine lifecycle support option to avoid unintended enrollment in RDS Extended Support when that is your policy.",
32
+ "Url": "https://hub.prowler.com/check/rds_instance_extended_support"
33
+ }
34
+ },
35
+ "Categories": [
36
+ "vulnerabilities"
37
+ ],
38
+ "DependsOn": [],
39
+ "RelatedTo": [],
40
+ "Notes": ""
41
+ }
@@ -0,0 +1,37 @@
1
+ """
2
+ Prowler check: rds_instance_extended_support
3
+
4
+ This check fails when an RDS DB instance is enrolled in Amazon RDS Extended Support.
5
+ Enrollment is exposed via the "EngineLifecycleSupport" attribute returned by DescribeDBInstances.
6
+ """
7
+
8
+ from prowler.lib.check.models import Check, Check_Report_AWS
9
+ from prowler.providers.aws.services.rds.rds_client import rds_client
10
+
11
+
12
+ class rds_instance_extended_support(Check):
13
+ def execute(self):
14
+ findings = []
15
+
16
+ for db_instance in rds_client.db_instances.values():
17
+ report = Check_Report_AWS(metadata=self.metadata(), resource=db_instance)
18
+
19
+ # EngineLifecycleSupport can be absent when Extended Support is not applicable.
20
+ lifecycle_support = getattr(db_instance, "engine_lifecycle_support", None)
21
+
22
+ if lifecycle_support == "open-source-rds-extended-support":
23
+ report.status = "FAIL"
24
+ report.status_extended = (
25
+ f"RDS instance {db_instance.id} ({db_instance.engine} {db_instance.engine_version}) "
26
+ f"is enrolled in RDS Extended Support (EngineLifecycleSupport={lifecycle_support})."
27
+ )
28
+ else:
29
+ report.status = "PASS"
30
+ report.status_extended = (
31
+ f"RDS instance {db_instance.id} ({db_instance.engine} {db_instance.engine_version}) "
32
+ "is not enrolled in RDS Extended Support."
33
+ )
34
+
35
+ findings.append(report)
36
+
37
+ return findings
@@ -59,6 +59,9 @@ class RDS(AWSService):
59
59
  endpoint=instance.get("Endpoint", {}),
60
60
  engine=instance["Engine"],
61
61
  engine_version=instance["EngineVersion"],
62
+ engine_lifecycle_support=instance.get(
63
+ "EngineLifecycleSupport"
64
+ ),
62
65
  status=instance["DBInstanceStatus"],
63
66
  public=instance.get("PubliclyAccessible", False),
64
67
  encrypted=instance["StorageEncrypted"],
@@ -531,6 +534,7 @@ class DBInstance(BaseModel):
531
534
  endpoint: dict
532
535
  engine: str
533
536
  engine_version: str
537
+ engine_lifecycle_support: Optional[str] = None
534
538
  status: str
535
539
  public: bool
536
540
  encrypted: bool
@@ -39,5 +39,5 @@
39
39
  ],
40
40
  "DependsOn": [],
41
41
  "RelatedTo": [],
42
- "Notes": ""
42
+ "Notes": "This check supports the `trusted_account_ids` configuration in config.yaml to allow specific cross-account access without triggering a finding."
43
43
  }
@@ -6,6 +6,7 @@ from prowler.providers.aws.services.s3.s3_client import s3_client
6
6
  class s3_bucket_cross_account_access(Check):
7
7
  def execute(self):
8
8
  findings = []
9
+ trusted_account_ids = s3_client.audit_config.get("trusted_account_ids", [])
9
10
  for bucket in s3_client.buckets.values():
10
11
  if bucket.policy is None:
11
12
  continue
@@ -19,7 +20,10 @@ class s3_bucket_cross_account_access(Check):
19
20
  f"S3 Bucket {bucket.name} does not have a bucket policy."
20
21
  )
21
22
  elif is_policy_public(
22
- bucket.policy, s3_client.audited_account, is_cross_account_allowed=False
23
+ bucket.policy,
24
+ s3_client.audited_account,
25
+ is_cross_account_allowed=False,
26
+ trusted_account_ids=trusted_account_ids,
23
27
  ):
24
28
  report.status = "FAIL"
25
29
  report.status_extended = f"S3 Bucket {bucket.name} has a bucket policy allowing cross account access."