mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(azure): add new check storage_ensure_private_endpoints_in_storage_accounts (#3326)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "storage_ensure_private_endpoints_in_storage_accounts",
|
||||
"CheckTitle": "Ensure Private Endpoints are used to access Storage Accounts",
|
||||
"CheckType": [],
|
||||
"ServiceName": "storage",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AzureStorageAccount",
|
||||
"Description": "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it.",
|
||||
"Risk": "Storage accounts that are not configured to use Private Endpoints are accessible over the public internet. This can lead to data exfiltration and other security issues.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/storage/common/storage-private-endpoints",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/StorageAccounts/private-endpoints.html#",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Use Private Endpoints to access Storage Accounts",
|
||||
"Url": "https://docs.microsoft.com/en-us/azure/storage/common/storage-private-endpoints"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"encryption"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.storage.storage_client import storage_client
|
||||
|
||||
|
||||
class storage_ensure_private_endpoints_in_storage_accounts(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, storage_accounts in storage_client.storage_accounts.items():
|
||||
for storage_account in storage_accounts:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = storage_account.name
|
||||
report.resource_id = storage_account.id
|
||||
if storage_account.private_endpoint_connections:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has private endpoint connections."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} does not have private endpoint connections."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from azure.mgmt.storage import StorageManagementClient
|
||||
from azure.mgmt.storage.v2022_09_01.models import NetworkRuleSet
|
||||
from azure.mgmt.storage.v2023_01_01.models import PrivateEndpointConnection
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.azure.lib.service.service import AzureService
|
||||
@@ -31,6 +32,7 @@ class Storage(AzureService):
|
||||
network_rule_set=storage_account.network_rule_set,
|
||||
encryption_type=storage_account.encryption.key_source,
|
||||
minimum_tls_version=storage_account.minimum_tls_version,
|
||||
private_endpoint_connections=storage_account.private_endpoint_connections,
|
||||
key_expiration_period_in_days=storage_account.key_policy.key_expiration_period_in_days,
|
||||
)
|
||||
)
|
||||
@@ -51,4 +53,5 @@ class Storage_Account:
|
||||
network_rule_set: NetworkRuleSet
|
||||
encryption_type: str
|
||||
minimum_tls_version: str
|
||||
private_endpoint_connections: PrivateEndpointConnection
|
||||
key_expiration_period_in_days: str
|
||||
|
||||
@@ -47,6 +47,13 @@ expected_packages = [
|
||||
name="prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts"
|
||||
),
|
||||
name="prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder("/root_dir/prowler/providers/azure/services/storage"),
|
||||
name="prowler.providers.azure.services.storage.storage_ensure_encryption_with_customer_managed_keys",
|
||||
@@ -82,6 +89,13 @@ def mock_list_modules(*_):
|
||||
name="prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts"
|
||||
),
|
||||
name="prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/storage"
|
||||
@@ -465,6 +479,10 @@ class Test_Check:
|
||||
"storage_key_rotation_90_days",
|
||||
"/root_dir/prowler/providers/azure/services/storage/storage_key_rotation_90_days",
|
||||
),
|
||||
(
|
||||
"storage_ensure_private_endpoints_in_storage_accounts",
|
||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts",
|
||||
),
|
||||
(
|
||||
"storage_ensure_encryption_with_customer_managed_keys",
|
||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys",
|
||||
|
||||
@@ -39,6 +39,7 @@ class Test_storage_blob_public_access_level_is_disabled:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -79,6 +80,7 @@ class Test_storage_blob_public_access_level_is_disabled:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ class Test_storage_default_network_access_rule_is_denied:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -81,6 +82,7 @@ class Test_storage_default_network_access_rule_is_denied:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -81,6 +82,7 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled:
|
||||
encryption_type=None,
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Test_storage_ensure_encryption_with_customer_managed_keys:
|
||||
encryption_type="None",
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -79,6 +80,7 @@ class Test_storage_ensure_encryption_with_customer_managed_keys:
|
||||
encryption_type="Microsoft.Keyvault",
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Test_storage_ensure_minimum_tls_version_12:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -79,6 +80,7 @@ class Test_storage_ensure_minimum_tls_version_12:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_2",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.storage.v2023_01_01.models import PrivateEndpointConnection
|
||||
|
||||
from prowler.providers.azure.services.storage.storage_service import Storage_Account
|
||||
|
||||
AZURE_SUSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_storage_ensure_private_endpoints_in_storage_accounts:
|
||||
def test_storage_ensure_private_endpoints_in_storage_accounts(self):
|
||||
storage_client = mock.MagicMock
|
||||
storage_client.storage_accounts = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts.storage_client",
|
||||
new=storage_client,
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts import (
|
||||
storage_ensure_private_endpoints_in_storage_accounts,
|
||||
)
|
||||
|
||||
check = storage_ensure_private_endpoints_in_storage_accounts()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_storage_ensure_private_endpoints_in_storage_accounts_no_endpoints(
|
||||
self,
|
||||
):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
storage_client = mock.MagicMock
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUSCRIPTION: [
|
||||
Storage_Account(
|
||||
id=storage_account_id,
|
||||
name=storage_account_name,
|
||||
enable_https_traffic_only=False,
|
||||
infrastructure_encryption=False,
|
||||
allow_blob_public_access=None,
|
||||
network_rule_set=None,
|
||||
encryption_type="None",
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts.storage_client",
|
||||
new=storage_client,
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts import (
|
||||
storage_ensure_private_endpoints_in_storage_accounts,
|
||||
)
|
||||
|
||||
check = storage_ensure_private_endpoints_in_storage_accounts()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Storage account {storage_account_name} from subscription {AZURE_SUSCRIPTION} does not have private endpoint connections."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == storage_account_id
|
||||
|
||||
def test_storage_ensure_private_endpoints_in_storage_accounts_has_endpoints(
|
||||
self,
|
||||
):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
storage_client = mock.MagicMock
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUSCRIPTION: [
|
||||
Storage_Account(
|
||||
id=storage_account_id,
|
||||
name=storage_account_name,
|
||||
enable_https_traffic_only=False,
|
||||
infrastructure_encryption=False,
|
||||
allow_blob_public_access=None,
|
||||
network_rule_set=None,
|
||||
encryption_type="None",
|
||||
minimum_tls_version=None,
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=PrivateEndpointConnection(),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts.storage_client",
|
||||
new=storage_client,
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_private_endpoints_in_storage_accounts.storage_ensure_private_endpoints_in_storage_accounts import (
|
||||
storage_ensure_private_endpoints_in_storage_accounts,
|
||||
)
|
||||
|
||||
check = storage_ensure_private_endpoints_in_storage_accounts()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Storage account {storage_account_name} from subscription {AZURE_SUSCRIPTION} has private endpoint connections."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == storage_account_id
|
||||
@@ -39,6 +39,7 @@ class Test_storage_infrastructure_encryption_is_enabled:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -79,6 +80,7 @@ class Test_storage_infrastructure_encryption_is_enabled:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Test_storage_key_rotation_90_dayss:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=expiration_days,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -80,6 +81,7 @@ class Test_storage_key_rotation_90_dayss:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_2",
|
||||
key_expiration_period_in_days=expiration_days,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -120,6 +122,7 @@ class Test_storage_key_rotation_90_dayss:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_2",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Test_storage_secure_transfer_required_is_enabled:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -79,6 +80,7 @@ class Test_storage_secure_transfer_required_is_enabled:
|
||||
encryption_type="None",
|
||||
minimum_tls_version="TLS1_1",
|
||||
key_expiration_period_in_days=None,
|
||||
private_endpoint_connections=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user