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:
Pedro Martín
2024-01-29 13:55:19 +01:00
committed by GitHub
parent ae1ab1d957
commit db4579435a
14 changed files with 204 additions and 0 deletions

View File

@@ -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": ""
}

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}

View File

@@ -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

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}

View File

@@ -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,
)
]
}