mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
feat(azure): add new check keyvault_access_only_through_private_endpoints (#8072)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
5b1e7bb7f9
commit
cbf2a28bac
@@ -37,6 +37,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Azure Databricks service integration for Azure provider, including the `databricks_workspace_vnet_injection_enabled` check [(#8008)](https://github.com/prowler-cloud/prowler/pull/8008)
|
||||
- Azure Databricks check `databricks_workspace_cmk_encryption_enabled` to ensure workspaces use customer-managed keys (CMK) for encryption at rest [(#8017)](https://github.com/prowler-cloud/prowler/pull/8017)
|
||||
- Add `storage_account_default_to_entra_authorization_enabled` check for Azure provider. [(#7981)](https://github.com/prowler-cloud/prowler/pull/7981)
|
||||
- `keyvault_ensure_public_network_access_disabled` check for Azure provider. [(#8072)](https://github.com/prowler-cloud/prowler/pull/8072)
|
||||
- New check `monitor_alert_service_health_exists` for Azure provider [(#8067)](https://github.com/prowler-cloud/prowler/pull/8067)
|
||||
- Replace `Domain.Read.All` with `Directory.Read.All` in Azure and M365 docs [(#8075)](https://github.com/prowler-cloud/prowler/pull/8075)
|
||||
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "keyvault_access_only_through_private_endpoints",
|
||||
"CheckTitle": "Ensure that public network access when using private endpoint is disabled.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "keyvault",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.KeyVault/vaults/{vault_name}",
|
||||
"Severity": "high",
|
||||
"ResourceType": "KeyVault",
|
||||
"Description": "Checks if Key Vaults with private endpoints have public network access disabled.",
|
||||
"Risk": "Allowing public network access to Key Vault when using private endpoint can expose sensitive data to unauthorized access.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/key-vault/general/network-security",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az keyvault update --resource-group <resource_group> --name <vault_name> --public-network-access disabled",
|
||||
"NativeIaC": "{\n \"type\": \"Microsoft.KeyVault/vaults\",\n \"apiVersion\": \"2022-07-01\",\n \"properties\": {\n \"publicNetworkAccess\": \"disabled\"\n }\n}",
|
||||
"Terraform": "resource \"azurerm_key_vault\" \"example\" {\n # ... other configuration ...\n\n public_network_access_enabled = false\n}",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/KeyVault/use-private-endpoints.html"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Disable public network access for Key Vaults that use private endpoint to ensure network traffic only flows through the private endpoint.",
|
||||
"Url": "https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.keyvault.keyvault_client import keyvault_client
|
||||
|
||||
|
||||
class keyvault_access_only_through_private_endpoints(Check):
|
||||
"""
|
||||
Ensure that Public Network Access when using Private Endpoint is disabled.
|
||||
|
||||
This check evaluates whether Azure Key Vaults with private endpoints configured have
|
||||
public network access disabled. Disabling public network access enhances security by
|
||||
isolating the Key Vault from the public internet, thereby reducing its exposure.
|
||||
|
||||
- PASS: The Key Vault has private endpoints and public network access is disabled.
|
||||
- FAIL: The Key Vault has private endpoints and public network access is enabled.
|
||||
"""
|
||||
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, key_vaults in keyvault_client.key_vaults.items():
|
||||
for keyvault in key_vaults:
|
||||
if (
|
||||
keyvault.properties
|
||||
and keyvault.properties.private_endpoint_connections
|
||||
):
|
||||
report = Check_Report_Azure(
|
||||
metadata=self.metadata(), resource=keyvault
|
||||
)
|
||||
report.subscription = subscription
|
||||
|
||||
if keyvault.properties.public_network_access_disabled:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has public network access disabled and is using private endpoints."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has public network access enabled while using private endpoints."
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -70,6 +70,14 @@ class KeyVault(AzureService):
|
||||
"enable_purge_protection",
|
||||
False,
|
||||
),
|
||||
public_network_access_disabled=(
|
||||
getattr(
|
||||
keyvault_properties,
|
||||
"public_network_access",
|
||||
"Enabled",
|
||||
)
|
||||
== "Disabled"
|
||||
),
|
||||
),
|
||||
keys=keys,
|
||||
secrets=secrets,
|
||||
@@ -247,6 +255,7 @@ class VaultProperties:
|
||||
private_endpoint_connections: List[PrivateEndpointConnection]
|
||||
enable_soft_delete: bool
|
||||
enable_purge_protection: bool
|
||||
public_network_access_disabled: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_keyvault_access_only_through_private_endpoints:
|
||||
def test_no_key_vaults(self):
|
||||
keyvault_client = mock.MagicMock
|
||||
keyvault_client.key_vaults = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints.keyvault_client",
|
||||
new=keyvault_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints import (
|
||||
keyvault_access_only_through_private_endpoints,
|
||||
)
|
||||
|
||||
check = keyvault_access_only_through_private_endpoints()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_key_vaults_no_private_endpoints(self):
|
||||
keyvault_client = mock.MagicMock
|
||||
keyvault_name = "Keyvault Name"
|
||||
keyvault_id = str(uuid4())
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints.keyvault_client",
|
||||
new=keyvault_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints import (
|
||||
keyvault_access_only_through_private_endpoints,
|
||||
)
|
||||
from prowler.providers.azure.services.keyvault.keyvault_service import (
|
||||
KeyVaultInfo,
|
||||
VaultProperties,
|
||||
)
|
||||
|
||||
keyvault_client.key_vaults = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
KeyVaultInfo(
|
||||
id=keyvault_id,
|
||||
name=keyvault_name,
|
||||
location="westeurope",
|
||||
resource_group="resource_group",
|
||||
properties=VaultProperties(
|
||||
tenant_id="tenantid",
|
||||
enable_rbac_authorization=False,
|
||||
private_endpoint_connections=[],
|
||||
enable_soft_delete=True,
|
||||
enable_purge_protection=True,
|
||||
public_network_access_disabled=False,
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
check = keyvault_access_only_through_private_endpoints()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_key_vaults_with_private_endpoints_public_access_enabled(self):
|
||||
keyvault_client = mock.MagicMock
|
||||
keyvault_name = "Keyvault Name"
|
||||
keyvault_id = str(uuid4())
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints.keyvault_client",
|
||||
new=keyvault_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints import (
|
||||
keyvault_access_only_through_private_endpoints,
|
||||
)
|
||||
from prowler.providers.azure.services.keyvault.keyvault_service import (
|
||||
KeyVaultInfo,
|
||||
PrivateEndpointConnection,
|
||||
VaultProperties,
|
||||
)
|
||||
|
||||
keyvault_client.key_vaults = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
KeyVaultInfo(
|
||||
id=keyvault_id,
|
||||
name=keyvault_name,
|
||||
location="westeurope",
|
||||
resource_group="resource_group",
|
||||
properties=VaultProperties(
|
||||
tenant_id="tenantid",
|
||||
enable_rbac_authorization=True,
|
||||
private_endpoint_connections=[
|
||||
PrivateEndpointConnection(id="id1")
|
||||
],
|
||||
enable_soft_delete=True,
|
||||
enable_purge_protection=True,
|
||||
public_network_access_disabled=False,
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
check = keyvault_access_only_through_private_endpoints()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Keyvault {keyvault_name} from subscription {AZURE_SUBSCRIPTION_ID} has public network access enabled while using private endpoints."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == keyvault_name
|
||||
assert result[0].resource_id == keyvault_id
|
||||
assert result[0].location == "westeurope"
|
||||
|
||||
def test_key_vaults_with_private_endpoints_public_access_disabled(self):
|
||||
keyvault_client = mock.MagicMock
|
||||
keyvault_name = "Keyvault Name"
|
||||
keyvault_id = str(uuid4())
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints.keyvault_client",
|
||||
new=keyvault_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.keyvault.keyvault_access_only_through_private_endpoints.keyvault_access_only_through_private_endpoints import (
|
||||
keyvault_access_only_through_private_endpoints,
|
||||
)
|
||||
from prowler.providers.azure.services.keyvault.keyvault_service import (
|
||||
KeyVaultInfo,
|
||||
PrivateEndpointConnection,
|
||||
VaultProperties,
|
||||
)
|
||||
|
||||
keyvault_client.key_vaults = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
KeyVaultInfo(
|
||||
id=keyvault_id,
|
||||
name=keyvault_name,
|
||||
location="westeurope",
|
||||
resource_group="resource_group",
|
||||
properties=VaultProperties(
|
||||
tenant_id="tenantid",
|
||||
enable_rbac_authorization=True,
|
||||
private_endpoint_connections=[
|
||||
PrivateEndpointConnection(id="id1")
|
||||
],
|
||||
enable_soft_delete=True,
|
||||
enable_purge_protection=True,
|
||||
public_network_access_disabled=True,
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
check = keyvault_access_only_through_private_endpoints()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Keyvault {keyvault_name} from subscription {AZURE_SUBSCRIPTION_ID} has public network access disabled and is using private endpoints."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == keyvault_name
|
||||
assert result[0].resource_id == keyvault_id
|
||||
assert result[0].location == "westeurope"
|
||||
Reference in New Issue
Block a user