feat(azure): add aks_cluster_azure_monitor_enabled check (#11029)

Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
This commit is contained in:
s1ns3nz0
2026-06-22 20:17:23 +09:00
committed by GitHub
parent 5d5f0676e0
commit 13f51de5c1
6 changed files with 193 additions and 0 deletions
+1
View File
@@ -26,6 +26,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `mysql_flexible_server_high_availability_enabled` check for Azure provider, verifying MySQL Flexible Servers have high availability enabled for automatic failover to a standby replica [(#11042)](https://github.com/prowler-cloud/prowler/pull/11042)
- `postgresql_flexible_server_geo_redundant_backup_enabled` check for Azure provider, verifying PostgreSQL Flexible Servers have geo-redundant backup enabled so backups are replicated to the paired region [(#11045)](https://github.com/prowler-cloud/prowler/pull/11045)
- `postgresql_flexible_server_high_availability_enabled` check for Azure provider, verifying PostgreSQL Flexible Servers have high availability enabled for automatic failover to a standby replica [(#11046)](https://github.com/prowler-cloud/prowler/pull/11046)
- `aks_cluster_azure_monitor_enabled` check for Azure provider, verifying AKS clusters have Azure Monitor (Container Insights) enabled for metrics, logs, and alerting [(#11029)](https://github.com/prowler-cloud/prowler/pull/11029)
- `aks_cluster_auto_upgrade_enabled` check for Azure provider [(#11027)](https://github.com/prowler-cloud/prowler/pull/11027)
- Public `Provider.get_class()` method that resolves a provider class by name for both built-in and external (entry-point) providers [(#11398)](https://github.com/prowler-cloud/prowler/pull/11398)
- Jira timeout preventing the calls from hanging indefinitely when the Jira endpoint is unreachable or slow [(#11602)](https://github.com/prowler-cloud/prowler/pull/11602)
@@ -1346,6 +1346,7 @@
}
],
"Checks": [
"aks_cluster_azure_monitor_enabled",
"defender_ensure_defender_cspm_is_on",
"monitor_alert_create_policy_assignment",
"monitor_alert_create_update_nsg",
@@ -0,0 +1,38 @@
{
"Provider": "azure",
"CheckID": "aks_cluster_azure_monitor_enabled",
"CheckTitle": "AKS cluster has Azure Monitor metrics enabled",
"CheckType": [],
"ServiceName": "aks",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "microsoft.containerservice/managedclusters",
"ResourceGroup": "container",
"Description": "**Azure Kubernetes Service** clusters are evaluated for **Azure Monitor managed service for Prometheus** (the cluster's `azureMonitorProfile.metrics` configuration). When enabled, cluster and workload metrics are collected into an Azure Monitor workspace for dashboards and alerting. This is distinct from Container Insights (the `omsagent` logs addon).",
"Risk": "Without **Azure Monitor metrics**, cluster degradation, resource exhaustion, and anomalous behavior go undetected. Lack of metric-based observability delays incident detection and hampers investigation after a security or availability event.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://learn.microsoft.com/en-us/azure/azure-monitor/containers/kubernetes-monitoring-enable",
"https://learn.microsoft.com/en-us/azure/azure-monitor/containers/prometheus-metrics-enable",
"https://learn.microsoft.com/en-us/azure/templates/microsoft.containerservice/managedclusters"
],
"Remediation": {
"Code": {
"CLI": "az aks update --resource-group <RESOURCE_GROUP> --name <CLUSTER_NAME> --enable-azure-monitor-metrics",
"NativeIaC": "```bicep\n// Bicep: AKS cluster with Azure Monitor managed Prometheus metrics enabled\nresource aks 'Microsoft.ContainerService/managedClusters@2024-02-01' = {\n name: '<example_resource_name>'\n location: resourceGroup().location\n properties: {\n azureMonitorProfile: {\n metrics: {\n enabled: true // CRITICAL: enables Azure Monitor managed service for Prometheus (metrics)\n }\n }\n }\n}\n```",
"Other": "1. Sign in to the Azure portal and open your AKS cluster\n2. In the left menu, select Monitoring > Insights\n3. Click Configure monitoring\n4. Ensure 'Enable Prometheus metrics' is selected and choose (or create) an Azure Monitor workspace\n5. Click Configure to enable Azure Monitor managed Prometheus metrics",
"Terraform": "```hcl\n# Terraform: AKS cluster with Azure Monitor managed Prometheus metrics enabled\nresource \"azurerm_kubernetes_cluster\" \"<example_resource_name>\" {\n name = \"<example_resource_name>\"\n location = \"<region>\"\n resource_group_name = \"<example_resource_name>\"\n dns_prefix = \"<example_resource_name>\"\n\n monitor_metrics {} # CRITICAL: enables Azure Monitor managed service for Prometheus (metrics)\n}\n```"
},
"Recommendation": {
"Text": "Enable **Azure Monitor managed service for Prometheus** on AKS clusters so cluster and workload metrics are collected into an Azure Monitor workspace. Pair it with alerting on cluster health and resource saturation, and consider also enabling Container Insights (logs) for full observability.",
"Url": "https://hub.prowler.com/check/aks_cluster_azure_monitor_enabled"
}
},
"Categories": [
"logging"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,32 @@
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.aks.aks_client import aks_client
class aks_cluster_azure_monitor_enabled(Check):
"""
Ensure Azure Monitor is enabled for AKS clusters.
This check evaluates whether each Azure Kubernetes Service cluster has Azure Monitor integration enabled for metrics collection, log aggregation, and alerting.
- PASS: The cluster has Azure Monitor enabled.
- FAIL: The cluster does not have Azure Monitor enabled.
"""
def execute(self) -> list[Check_Report_Azure]:
findings = []
for subscription_name, clusters in aks_client.clusters.items():
for cluster in clusters.values():
report = Check_Report_Azure(metadata=self.metadata(), resource=cluster)
report.subscription = subscription_name
if cluster.azure_monitor_enabled:
report.status = "PASS"
report.status_extended = f"Cluster '{cluster.name}' has Azure Monitor managed Prometheus metrics enabled."
else:
report.status = "FAIL"
report.status_extended = f"Cluster '{cluster.name}' does not have Azure Monitor managed Prometheus metrics enabled."
findings.append(report)
return findings
@@ -0,0 +1,121 @@
from importlib import import_module
from unittest import mock
from uuid import uuid4
import pytest
from prowler.providers.azure.services.aks.aks_service import Cluster
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
set_mocked_azure_provider,
)
CHECK_MODULE = (
"prowler.providers.azure.services.aks.aks_cluster_azure_monitor_enabled."
"aks_cluster_azure_monitor_enabled"
)
CHECK_CLIENT_PATCH = f"{CHECK_MODULE}.aks_client"
def get_check_class():
return import_module(CHECK_MODULE).aks_cluster_azure_monitor_enabled
def build_cluster(azure_monitor_enabled):
return Cluster(
id=str(uuid4()),
name="test-cluster",
public_fqdn="test.azmk8s.io",
private_fqdn=None,
network_policy=None,
agent_pool_profiles=[],
rbac_enabled=True,
location="eastus",
azure_monitor_enabled=azure_monitor_enabled,
)
class Test_aks_cluster_azure_monitor_enabled:
def test_no_subscriptions(self):
aks_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
CHECK_CLIENT_PATCH,
new=aks_client,
),
):
aks_cluster_azure_monitor_enabled = get_check_class()
aks_client.clusters = {}
check = aks_cluster_azure_monitor_enabled()
result = check.execute()
assert len(result) == 0
def test_pass(self):
aks_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
CHECK_CLIENT_PATCH,
new=aks_client,
),
):
aks_cluster_azure_monitor_enabled = get_check_class()
cluster = build_cluster(azure_monitor_enabled=True)
aks_client.clusters = {AZURE_SUBSCRIPTION_ID: {cluster.id: cluster}}
check = aks_cluster_azure_monitor_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "Cluster 'test-cluster' has Azure Monitor managed Prometheus metrics enabled."
)
assert result[0].resource_name == "test-cluster"
assert result[0].resource_id == cluster.id
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].location == "eastus"
@pytest.mark.parametrize("azure_monitor_enabled", [False, None])
def test_fail(self, azure_monitor_enabled):
aks_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
CHECK_CLIENT_PATCH,
new=aks_client,
),
):
aks_cluster_azure_monitor_enabled = get_check_class()
cluster = build_cluster(azure_monitor_enabled=azure_monitor_enabled)
aks_client.clusters = {AZURE_SUBSCRIPTION_ID: {cluster.id: cluster}}
check = aks_cluster_azure_monitor_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Cluster 'test-cluster' does not have Azure Monitor managed Prometheus metrics enabled."
)
assert result[0].resource_name == "test-cluster"
assert result[0].resource_id == cluster.id
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].location == "eastus"