diff --git a/CHANGELOG.md b/CHANGELOG.md index ee90a70e..cc2af078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## v0.47 [2024-08-02] + +_Enhancements_ + +- Added the following controls to the `All Controls` benchmark: ([#274](https://github.com/turbot/steampipe-mod-azure-compliance/pull/274)) + - `application_gateway_waf_uses_specified_mode` + - `application_insights_block_log_ingestion_and_querying_from_public` + - `log_analytics_workspace_block_log_ingestion_and_querying_from_public` + - `log_analytics_workspace_block_non_azure_ingestion` + +_Bug fixes_ + +- Fixed the `storage_account_block_public_access` query to check if the `public_network_access` column is set to `disabled` as per the CIS documentation. ([#277](https://github.com/turbot/steampipe-mod-azure-compliance/pull/277)) + ## v0.46 [2024-06-14] _What's new?_ diff --git a/all_controls/monitor.sp b/all_controls/monitor.sp index a8a2e683..479f08a5 100644 --- a/all_controls/monitor.sp +++ b/all_controls/monitor.sp @@ -8,7 +8,10 @@ benchmark "all_controls_monitor" { title = "Monitor" description = "This section contains recommendations for configuring Monitor resources." children = [ + control.application_insights_block_log_ingestion_and_querying_from_public, control.application_insights_linked_to_log_analytics_workspace, + control.log_analytics_workspace_block_log_ingestion_and_querying_from_public, + control.log_analytics_workspace_block_non_azure_ingestion, control.log_profile_enabled_for_all_subscription, control.monitor_diagnostic_settings_captures_proper_categories, control.monitor_log_alert_create_policy_assignment, diff --git a/all_controls/network.sp b/all_controls/network.sp index df55975d..30550665 100644 --- a/all_controls/network.sp +++ b/all_controls/network.sp @@ -9,6 +9,7 @@ benchmark "all_controls_network" { description = "This section contains recommendations for configuring Network resources." children = [ control.application_gateway_waf_enabled, + control.application_gateway_waf_uses_specified_mode, control.network_bastion_host_min_1, control.network_ddos_enabled, control.network_lb_no_basic_sku, diff --git a/rbi_itf_nbfc_v2017/rbi_itf_nbfc_is_audit.sp b/rbi_itf_nbfc_v2017/rbi_itf_nbfc_is_audit.sp index 1eb99d1f..f0c80426 100644 --- a/rbi_itf_nbfc_v2017/rbi_itf_nbfc_is_audit.sp +++ b/rbi_itf_nbfc_v2017/rbi_itf_nbfc_is_audit.sp @@ -12,6 +12,7 @@ benchmark "rbi_itf_nbfc_v2017_is_audit_5" { children = [ benchmark.rbi_itf_nbfc_v2017_is_audit_5_2, control.application_gateway_waf_enabled, + control.application_gateway_waf_uses_specified_mode, control.compute_vm_remote_access_restricted_all_ports, control.compute_vm_tcp_udp_access_restricted_internet, control.cosmosdb_account_with_firewall_rules, diff --git a/rbi_itf_nbfc_v2017/rbi_itf_nbfc_it_information_and_cyber_security.sp b/rbi_itf_nbfc_v2017/rbi_itf_nbfc_it_information_and_cyber_security.sp index e3ab8dbe..f14296d9 100644 --- a/rbi_itf_nbfc_v2017/rbi_itf_nbfc_it_information_and_cyber_security.sp +++ b/rbi_itf_nbfc_v2017/rbi_itf_nbfc_it_information_and_cyber_security.sp @@ -97,12 +97,15 @@ benchmark "rbi_itf_nbfc_v2017_it_information_and_cyber_security_3_1_f" { benchmark "rbi_itf_nbfc_v2017_it_information_and_cyber_security_3_1_g" { title = "Trails-3.1.g" children = [ + control.application_insights_block_log_ingestion_and_querying_from_public, control.application_insights_linked_to_log_analytics_workspace, control.compute_vm_log_analytics_agent_installed, control.compute_vm_network_traffic_data_collection_linux_agent_installed, control.compute_vm_network_traffic_data_collection_windows_agent_installed, control.compute_vm_scale_set_log_analytics_agent_installed, control.iam_subscription_owner_max_3, + control.log_analytics_workspace_block_log_ingestion_and_querying_from_public, + control.log_analytics_workspace_block_non_azure_ingestion, control.log_profile_enabled_for_all_subscription, control.monitor_log_profile_enabled_for_all_categories, control.monitor_log_profile_enabled_for_all_regions, diff --git a/regulatory_compliance/monitor.sp b/regulatory_compliance/monitor.sp index dd28c583..a4c23ca8 100644 --- a/regulatory_compliance/monitor.sp +++ b/regulatory_compliance/monitor.sp @@ -253,6 +253,36 @@ control "monitor_logs_storage_container_insights_activity_logs_not_public_access tags = local.regulatory_compliance_monitor_common_tags } +control "log_analytics_workspace_block_log_ingestion_and_querying_from_public" { + title = "Log Analytics workspaces should block log ingestion and querying from public networks" + description = "Improve workspace security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs on this workspace. Learn more at https://aka.ms/AzMonPrivateLink#configure-log-analytics." + query = query.log_analytics_workspace_block_log_ingestion_and_querying_from_public + + tags = merge(local.regulatory_compliance_monitor_common_tags, { + rbi_itf_nbfc_v2017 = "true" + }) +} + +control "log_analytics_workspace_block_non_azure_ingestion" { + title = "Log Analytics Workspaces should block non-Azure Active Directory based ingestion" + description = "Enforcing log ingestion to require Azure Active Directory authentication prevents unauthenticated logs from an attacker which could lead to incorrect status, false alerts, and incorrect logs stored in the system." + query = query.log_analytics_workspace_block_non_azure_ingestion + + tags = merge(local.regulatory_compliance_monitor_common_tags, { + rbi_itf_nbfc_v2017 = "true" + }) +} + +control "application_insights_block_log_ingestion_and_querying_from_public" { + title = "Application Insights components should block log ingestion and querying from public networks" + description = "Improve Application Insights security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs of this component. Learn more at https://aka.ms/AzMonPrivateLink#configure-application-insights." + query = query.application_insights_block_log_ingestion_and_querying_from_public + + tags = merge(local.regulatory_compliance_monitor_common_tags, { + rbi_itf_nbfc_v2017 = "true" + }) +} + query "monitor_log_profile_enabled_for_all_categories" { sql = <<-EOQ select @@ -1249,3 +1279,66 @@ query "application_insights_linked_to_log_analytics_workspace" { left join azure_subscription sub on sub.subscription_id = a.subscription_id; EOQ } + +query "application_insights_block_log_ingestion_and_querying_from_public" { + sql = <<-EOQ + select + a.id as resource, + case + when type = 'microsoft.insights/components' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then 'ok' + else 'alarm' + end as status, + case + when type = 'microsoft.insights/components' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then a.name || ' allows log ingestion and querying from public network.' + else a.name || ' does not allow log ingestion and querying from public network.' + end as reason + ${local.tag_dimensions_sql} + ${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "a.")} + ${replace(local.common_dimensions_qualifier_subscription_sql, "__QUALIFIER__", "sub.")} + from + azure_application_insight as a + left join azure_subscription sub on sub.subscription_id = a.subscription_id; + EOQ +} + +query "log_analytics_workspace_block_log_ingestion_and_querying_from_public" { + sql = <<-EOQ + select + w.id as resource, + case + when type = 'Microsoft.OperationalInsights/workspaces' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then 'ok' + else 'alarm' + end as status, + case + when type = 'Microsoft.OperationalInsights/workspaces' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then w.name || ' workspace allows log ingestion and querying from public network.' + else w.name || ' workspace does not allow log ingestion and querying from public network.' + end as reason + ${local.tag_dimensions_sql} + ${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "w.")} + ${replace(local.common_dimensions_qualifier_subscription_sql, "__QUALIFIER__", "sub.")} + from + azure_log_analytics_workspace as w + left join azure_subscription sub on sub.subscription_id = w.subscription_id; + EOQ +} + +query "log_analytics_workspace_block_non_azure_ingestion" { + sql = <<-EOQ + select + w.id as resource, + case + when type = 'Microsoft.OperationalInsights/workspaces' and disable_local_auth = 'true' then 'alarm' + else 'ok' + end as status, + case + when type = 'Microsoft.OperationalInsights/workspaces' and disable_local_auth = 'true' then w.name || ' workspace allows non-Azure log ingestion.' + else w.name || ' workspace does not allow non-Azure log ingestion.' + end as reason + ${local.tag_dimensions_sql} + ${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "w.")} + ${replace(local.common_dimensions_qualifier_subscription_sql, "__QUALIFIER__", "sub.")} + from + azure_log_analytics_workspace as w + left join azure_subscription sub on sub.subscription_id = w.subscription_id; + EOQ +} \ No newline at end of file diff --git a/regulatory_compliance/network.sp b/regulatory_compliance/network.sp index fa88a5dc..544540ac 100644 --- a/regulatory_compliance/network.sp +++ b/regulatory_compliance/network.sp @@ -381,6 +381,16 @@ control "network_watcher_flow_log_traffic_analytics_enabled" { }) } +control "application_gateway_waf_uses_specified_mode" { + title = "Web Application Firewall (WAF) should use the specified mode for Application Gateway" + description = "Mandates the use of 'Detection' or 'Prevention' mode to be active on all Web Application Firewall policies for Application Gateway." + query = query.application_gateway_waf_uses_specified_mode + + tags = merge(local.regulatory_compliance_network_common_tags, { + rbi_itf_nbfc_v2017 = "true" + }) +} + query "network_security_group_remote_access_restricted" { sql = <<-EOQ with network_sg as ( @@ -2121,4 +2131,25 @@ query "network_watcher_flow_log_traffic_analytics_enabled" { azure_network_watcher_flow_log as sg join azure_subscription sub on sub.subscription_id = sg.subscription_id; EOQ -} \ No newline at end of file +} + +query "application_gateway_waf_uses_specified_mode" { + sql = <<-EOQ + select + ag.id as resource, + case + when (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') in ('Prevention','Detection') then 'ok' + else 'alarm' + end as status, + case + when (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') in ('Prevention','Detection') then ag.name || ' WAF mode is set to ' || (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') || '.' + else ag.name || ' WAF mode is not set to Prevention or Detection mode.' + end as reason + ${local.tag_dimensions_sql} + ${replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "ag.")} + ${replace(local.common_dimensions_qualifier_subscription_sql, "__QUALIFIER__", "sub.")} + from + azure_application_gateway as ag + join azure_subscription as sub on sub.subscription_id = ag.subscription_id; + EOQ +} diff --git a/regulatory_compliance/storage.sp b/regulatory_compliance/storage.sp index 8a5a5023..7d9750d7 100644 --- a/regulatory_compliance/storage.sp +++ b/regulatory_compliance/storage.sp @@ -376,17 +376,11 @@ query "storage_account_block_public_access" { select sa.id as resource, case - when sa.id not like '%/resourceGroups/aro-%' - and (sa.name not like 'cluster%' or sa.name not like 'imageregistry%') - and sa.allow_blob_public_access = 'false' - then 'ok' + when lower(sa.public_network_access) = 'disabled' then 'ok' else 'alarm' end as status, case - when sa.id not like '%/resourceGroups/aro-%' - and (sa.name not like 'cluster%' or sa.name not like 'imageregistry%') - and sa.allow_blob_public_access = 'false' - then sa.name || ' not publicy accessible.' + when lower(sa.public_network_access) = 'disabled' then sa.name || ' not publicy accessible.' else sa.name || ' publicy accessible.' end as reason ${local.tag_dimensions_sql}