mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-18 01:14:16 +00:00
fix(azure): consolidate file share properties to the storage account level (#8087)
(cherry picked from commit e0465f2aa2)
# Conflicts:
# prowler/CHANGELOG.md
# prowler/providers/azure/services/storage/storage_ensure_file_shares_soft_delete_is_enabled/storage_ensure_file_shares_soft_delete_is_enabled.py
# prowler/providers/azure/services/storage/storage_service.py
# tests/providers/azure/services/storage/storage_ensure_file_shares_soft_delete_is_enabled/storage_ensure_file_shares_soft_delete_is_enabled_test.py
# tests/providers/azure/services/storage/storage_service_test.py
This commit is contained in:
1 parent
1e2ab0e617
commit
7dd2038cc6
5 files changed
+347
No files matched your search
@@ -27,7 +27,25 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `storage_ensure_file_shares_soft_delete_is_enabled` check for Azure provider [(#7966)](https://github.com/prowler-cloud/prowler/pull/7966)
|
||||
- Make `validate_mutelist` method static inside `Mutelist` class [(#7811)](https://github.com/prowler-cloud/prowler/pull/7811)
|
||||
- Avoid bypassing IAM check using wildcards [(#7708)](https://github.com/prowler-cloud/prowler/pull/7708)
|
||||
<<<<<<< HEAD
|
||||
- Add new method to authenticate in AppInsights in check `app_function_application_insights_enabled` [(#7763)](https://github.com/prowler-cloud/prowler/pull/7763)
|
||||
=======
|
||||
- `storage_blob_versioning_is_enabled` new check for Azure provider [(#7927)](https://github.com/prowler-cloud/prowler/pull/7927)
|
||||
- New method to authenticate in AppInsights in check `app_function_application_insights_enabled` [(#7763)](https://github.com/prowler-cloud/prowler/pull/7763)
|
||||
- ISO 27001 2022 for M365 provider. [(#7985)](https://github.com/prowler-cloud/prowler/pull/7985)
|
||||
- `codebuild_project_uses_allowed_github_organizations` check for AWS provider [(#7595)](https://github.com/prowler-cloud/prowler/pull/7595)
|
||||
- IaC provider [(#7852)](https://github.com/prowler-cloud/prowler/pull/7852)
|
||||
- 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)
|
||||
- Replace `Domain.Read.All` with `Directory.Read.All` in Azure and M365 docs [(#8075)](https://github.com/prowler-cloud/prowler/pull/8075)
|
||||
|
||||
### Fixed
|
||||
- Consolidate Azure Storage file service properties to the account level, improving the accuracy of the `storage_ensure_file_shares_soft_delete_is_enabled` check [(#8087)](https://github.com/prowler-cloud/prowler/pull/8087)
|
||||
|
||||
### Removed
|
||||
- OCSF version number references to point always to the latest [(#8064)](https://github.com/prowler-cloud/prowler/pull/8064)
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
|
||||
---
|
||||
## [v5.7.5] (Prowler UNRELEASED)
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.storage.storage_client import storage_client
|
||||
|
||||
|
||||
class storage_ensure_file_shares_soft_delete_is_enabled(Check):
|
||||
def execute(self) -> list:
|
||||
findings = []
|
||||
for subscription, storage_accounts in storage_client.storage_accounts.items():
|
||||
for storage_account in storage_accounts:
|
||||
if getattr(storage_account, "file_service_properties", None):
|
||||
report = Check_Report_Azure(
|
||||
metadata=self.metadata(),
|
||||
resource=storage_account.file_service_properties,
|
||||
)
|
||||
report.subscription = subscription
|
||||
report.resource_name = storage_account.name
|
||||
report.location = storage_account.location
|
||||
|
||||
if (
|
||||
storage_account.file_service_properties.share_delete_retention_policy.enabled
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"File share soft delete is enabled for storage account {storage_account.name} with a retention period of {storage_account.file_service_properties.share_delete_retention_policy.days} days."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"File share soft delete is not enabled for storage account {storage_account.name}."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
|
||||
from azure.mgmt.storage import StorageManagementClient
|
||||
from pydantic import BaseModel
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.azure.azure_provider import AzureProvider
|
||||
@@ -122,6 +123,47 @@ class Storage(AzureService):
|
||||
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
def _get_file_share_properties(self):
|
||||
logger.info("Storage - Getting file share properties...")
|
||||
for subscription, accounts in self.storage_accounts.items():
|
||||
client = self.clients[subscription]
|
||||
for account in accounts:
|
||||
try:
|
||||
file_service_properties = (
|
||||
client.file_services.get_service_properties(
|
||||
account.resouce_group_name, account.name
|
||||
)
|
||||
)
|
||||
share_delete_retention_policy = getattr(
|
||||
file_service_properties,
|
||||
"share_delete_retention_policy",
|
||||
None,
|
||||
)
|
||||
account.file_service_properties = FileServiceProperties(
|
||||
id=file_service_properties.id,
|
||||
name=file_service_properties.name,
|
||||
type=file_service_properties.type,
|
||||
share_delete_retention_policy=DeleteRetentionPolicy(
|
||||
enabled=getattr(
|
||||
share_delete_retention_policy,
|
||||
"enabled",
|
||||
False,
|
||||
),
|
||||
days=getattr(
|
||||
share_delete_retention_policy,
|
||||
"days",
|
||||
0,
|
||||
),
|
||||
),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
|
||||
@dataclass
|
||||
class DeleteRetentionPolicy:
|
||||
@@ -151,6 +193,27 @@ class PrivateEndpointConnection:
|
||||
type: str
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
class ReplicationSettings(Enum):
|
||||
STANDARD_LRS = "Standard_LRS"
|
||||
STANDARD_GRS = "Standard_GRS"
|
||||
STANDARD_RAGRS = "Standard_RAGRS"
|
||||
STANDARD_ZRS = "Standard_ZRS"
|
||||
PREMIUM_LRS = "Premium_LRS"
|
||||
PREMIUM_ZRS = "Premium_ZRS"
|
||||
STANDARD_GZRS = "Standard_GZRS"
|
||||
STANDARD_RAGZRS = "Standard_RAGZRS"
|
||||
|
||||
|
||||
class FileServiceProperties(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
share_delete_retention_policy: DeleteRetentionPolicy
|
||||
|
||||
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
@dataclass
|
||||
class Account:
|
||||
id: str
|
||||
@@ -166,3 +229,8 @@ class Account:
|
||||
key_expiration_period_in_days: str
|
||||
location: str
|
||||
blob_properties: Optional[BlobProperties] = None
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
default_to_entra_authorization: bool = False
|
||||
file_service_properties: Optional[FileServiceProperties] = None
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.storage.storage_service import (
|
||||
Account,
|
||||
DeleteRetentionPolicy,
|
||||
FileServiceProperties,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_storage_ensure_file_shares_soft_delete_is_enabled:
|
||||
def test_no_storage_accounts(self):
|
||||
storage_client = mock.MagicMock
|
||||
storage_client.storage_accounts = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled import (
|
||||
storage_ensure_file_shares_soft_delete_is_enabled,
|
||||
)
|
||||
|
||||
check = storage_ensure_file_shares_soft_delete_is_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_storage_account_no_file_properties(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
storage_client = mock.MagicMock
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
Account(
|
||||
id=storage_account_id,
|
||||
name=storage_account_name,
|
||||
resouce_group_name=None,
|
||||
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,
|
||||
location="westeurope",
|
||||
private_endpoint_connections=None,
|
||||
file_service_properties=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled import (
|
||||
storage_ensure_file_shares_soft_delete_is_enabled,
|
||||
)
|
||||
|
||||
check = storage_ensure_file_shares_soft_delete_is_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_file_share_soft_delete_disabled(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
storage_client = mock.MagicMock
|
||||
retention_policy = DeleteRetentionPolicy(enabled=False, days=0)
|
||||
file_service_properties = FileServiceProperties(
|
||||
id=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/prowler-resource-group/providers/Microsoft.Storage/storageAccounts/{storage_account_name}/fileServices/default",
|
||||
name="default",
|
||||
type="Microsoft.Storage/storageAccounts/fileServices",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
)
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
Account(
|
||||
id=storage_account_id,
|
||||
name=storage_account_name,
|
||||
resouce_group_name=None,
|
||||
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,
|
||||
location="westeurope",
|
||||
private_endpoint_connections=None,
|
||||
file_service_properties=file_service_properties,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled import (
|
||||
storage_ensure_file_shares_soft_delete_is_enabled,
|
||||
)
|
||||
|
||||
check = storage_ensure_file_shares_soft_delete_is_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"File share soft delete is not enabled for storage account {storage_account_name}."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == file_service_properties.id
|
||||
assert result[0].location == "westeurope"
|
||||
|
||||
def test_file_share_soft_delete_enabled(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
storage_client = mock.MagicMock
|
||||
retention_policy = DeleteRetentionPolicy(enabled=True, days=7)
|
||||
file_service_properties = FileServiceProperties(
|
||||
id=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/prowler-resource-group/providers/Microsoft.Storage/storageAccounts/{storage_account_name}/fileServices/default",
|
||||
name="default",
|
||||
type="Microsoft.Storage/storageAccounts/fileServices",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
)
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
Account(
|
||||
id=storage_account_id,
|
||||
name=storage_account_name,
|
||||
resouce_group_name=None,
|
||||
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,
|
||||
location="westeurope",
|
||||
private_endpoint_connections=None,
|
||||
file_service_properties=file_service_properties,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_ensure_file_shares_soft_delete_is_enabled.storage_ensure_file_shares_soft_delete_is_enabled import (
|
||||
storage_ensure_file_shares_soft_delete_is_enabled,
|
||||
)
|
||||
|
||||
check = storage_ensure_file_shares_soft_delete_is_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"File share soft delete is enabled for storage account {storage_account_name} with a retention period of {retention_policy.days} days."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == file_service_properties.id
|
||||
assert result[0].location == "westeurope"
|
||||
@@ -3,6 +3,12 @@ from unittest.mock import patch
|
||||
from prowler.providers.azure.services.storage.storage_service import (
|
||||
Account,
|
||||
BlobProperties,
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
DeleteRetentionPolicy,
|
||||
FileServiceProperties,
|
||||
ReplicationSettings,
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
Storage,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
@@ -19,6 +25,16 @@ def mock_storage_get_storage_accounts(_):
|
||||
default_service_version=None,
|
||||
container_delete_retention_policy=None,
|
||||
)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
retention_policy = DeleteRetentionPolicy(enabled=True, days=7)
|
||||
file_service_properties = FileServiceProperties(
|
||||
id="id",
|
||||
name="name",
|
||||
type="type",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
)
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
return {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
Account(
|
||||
@@ -35,6 +51,14 @@ def mock_storage_get_storage_accounts(_):
|
||||
private_endpoint_connections=None,
|
||||
location="westeurope",
|
||||
blob_properties=blob_properties,
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
default_to_entra_authorization=True,
|
||||
replication_settings=ReplicationSettings.STANDARD_LRS,
|
||||
allow_cross_tenant_replication=True,
|
||||
allow_shared_key_access=True,
|
||||
file_service_properties=file_service_properties,
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -143,3 +167,16 @@ class Test_Storage_Service:
|
||||
].blob_properties.container_delete_retention_policy
|
||||
is None
|
||||
)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
def test_get_file_service_properties(self):
|
||||
storage = Storage(set_mocked_azure_provider())
|
||||
account = storage.storage_accounts[AZURE_SUBSCRIPTION_ID][0]
|
||||
assert hasattr(account, "file_service_properties")
|
||||
assert (
|
||||
account.file_service_properties.share_delete_retention_policy.enabled
|
||||
is True
|
||||
)
|
||||
assert account.file_service_properties.share_delete_retention_policy.days == 7
|
||||
>>>>>>> e0465f2aa (fix(azure): consolidate file share properties to the storage account level (#8087))
|
||||
Reference in new issue
Block a user