mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
Merge branch 'master' into PRWLR-6707-create-a-way-of-reporting-for-prowler-threatscore
This commit is contained in:
@@ -5,6 +5,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
## [v5.9.0] (Prowler UNRELEASED)
|
||||
|
||||
### Added
|
||||
- `storage_smb_channel_encryption_with_secure_algorithm` check for Azure provider [(#8123)](https://github.com/prowler-cloud/prowler/pull/8123)
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -158,6 +158,21 @@ class Storage(AzureService):
|
||||
"share_delete_retention_policy",
|
||||
None,
|
||||
)
|
||||
|
||||
smb_channel_encryption_raw = getattr(
|
||||
getattr(
|
||||
getattr(
|
||||
file_service_properties,
|
||||
"protocol_settings",
|
||||
None,
|
||||
),
|
||||
"smb",
|
||||
None,
|
||||
),
|
||||
"channel_encryption",
|
||||
None,
|
||||
)
|
||||
|
||||
account.file_service_properties = FileServiceProperties(
|
||||
id=file_service_properties.id,
|
||||
name=file_service_properties.name,
|
||||
@@ -174,6 +189,13 @@ class Storage(AzureService):
|
||||
0,
|
||||
),
|
||||
),
|
||||
smb_protocol_settings=SMBProtocolSettings(
|
||||
channel_encryption=(
|
||||
smb_channel_encryption_raw.rstrip(";").split(";")
|
||||
if smb_channel_encryption_raw
|
||||
else []
|
||||
)
|
||||
),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -221,11 +243,16 @@ class ReplicationSettings(Enum):
|
||||
STANDARD_RAGZRS = "Standard_RAGZRS"
|
||||
|
||||
|
||||
class SMBProtocolSettings(BaseModel):
|
||||
channel_encryption: list[str]
|
||||
|
||||
|
||||
class FileServiceProperties(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
share_delete_retention_policy: DeleteRetentionPolicy
|
||||
smb_protocol_settings: SMBProtocolSettings
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "storage_smb_channel_encryption_with_secure_algorithm",
|
||||
"CheckTitle": "Ensure SMB channel encryption uses a secure algorithm for SMB file shares",
|
||||
"CheckType": [],
|
||||
"ServiceName": "storage",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}/fileServices/default",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AzureStorageAccount",
|
||||
"Description": "Implement SMB channel encryption with a secure algorithm for SMB file shares to ensure data confidentiality and integrity in transit.",
|
||||
"Risk": "Not using the recommended SMB channel encryption may expose data transmitted over SMB channels to unauthorized interception and tampering.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-files#recommendations-for-smb-file-shares",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az storage account file-service-properties update --resource-group <resource-group> --account-name <storage-account> --channel-encryption AES-256-GCM",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Use the portal, CLI or PowerShell to set the SMB channel encryption to a secure algorithm.",
|
||||
"Url": "https://learn.microsoft.com/en-us/azure/storage/files/files-smb-protocol?tabs=azure-portal#smb-security-settings"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This check passes if SMB channel encryption is set to a secure algorithm."
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.storage.storage_client import storage_client
|
||||
|
||||
SECURE_ENCRYPTION_ALGORITHMS = ["AES-256-GCM"]
|
||||
|
||||
|
||||
class storage_smb_channel_encryption_with_secure_algorithm(Check):
|
||||
"""
|
||||
Ensure SMB channel encryption for file shares is set to the recommended algorithm (AES-256-GCM or higher).
|
||||
|
||||
This check evaluates whether SMB file shares are configured to use only the recommended SMB channel encryption algorithms.
|
||||
- PASS: Storage account has the recommended SMB channel encryption (AES-256-GCM or higher) enabled for file shares.
|
||||
- FAIL: Storage account does not have the recommended SMB channel encryption enabled for file shares or uses an unsupported algorithm.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[Check_Report_Azure]:
|
||||
findings = []
|
||||
for subscription, storage_accounts in storage_client.storage_accounts.items():
|
||||
for account in storage_accounts:
|
||||
if account.file_service_properties:
|
||||
pretty_current_algorithms = (
|
||||
", ".join(
|
||||
account.file_service_properties.smb_protocol_settings.channel_encryption
|
||||
)
|
||||
if account.file_service_properties.smb_protocol_settings.channel_encryption
|
||||
else "none"
|
||||
)
|
||||
report = Check_Report_Azure(
|
||||
metadata=self.metadata(),
|
||||
resource=account.file_service_properties,
|
||||
)
|
||||
report.subscription = subscription
|
||||
report.resource_name = account.name
|
||||
|
||||
if (
|
||||
not account.file_service_properties.smb_protocol_settings.channel_encryption
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Storage account {account.name} from subscription {subscription} does not have SMB channel encryption enabled for file shares."
|
||||
elif any(
|
||||
algorithm in SECURE_ENCRYPTION_ALGORITHMS
|
||||
for algorithm in account.file_service_properties.smb_protocol_settings.channel_encryption
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Storage account {account.name} from subscription {subscription} has a secure algorithm for SMB channel encryption ({', '.join(SECURE_ENCRYPTION_ALGORITHMS)}) enabled for file shares since it supports {pretty_current_algorithms}."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Storage account {account.name} from subscription {subscription} does not have SMB channel encryption with a secure algorithm for file shares since it supports {pretty_current_algorithms}."
|
||||
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -110,7 +110,6 @@ class TestAzureProvider:
|
||||
return_value={},
|
||||
),
|
||||
):
|
||||
|
||||
with pytest.raises(AzureNoAuthenticationMethodError) as exception:
|
||||
_ = AzureProvider(
|
||||
az_cli_auth,
|
||||
@@ -151,7 +150,6 @@ class TestAzureProvider:
|
||||
return_value={},
|
||||
),
|
||||
):
|
||||
|
||||
with pytest.raises(AzureBrowserAuthNoTenantIDError) as exception:
|
||||
_ = AzureProvider(
|
||||
az_cli_auth,
|
||||
@@ -193,7 +191,6 @@ class TestAzureProvider:
|
||||
return_value={},
|
||||
),
|
||||
):
|
||||
|
||||
with pytest.raises(AzureTenantIDNoBrowserAuthError) as exception:
|
||||
_ = AzureProvider(
|
||||
az_cli_auth,
|
||||
@@ -224,7 +221,6 @@ class TestAzureProvider:
|
||||
"prowler.providers.azure.azure_provider.SubscriptionClient"
|
||||
) as mock_resource_client,
|
||||
):
|
||||
|
||||
# Mock the return value of DefaultAzureCredential
|
||||
mock_credentials = MagicMock()
|
||||
mock_credentials.get_token.return_value = AccessToken(
|
||||
@@ -266,7 +262,6 @@ class TestAzureProvider:
|
||||
"prowler.providers.azure.azure_provider.AzureProvider.validate_static_credentials"
|
||||
) as mock_validate_static_credentials,
|
||||
):
|
||||
|
||||
# Mock the return value of DefaultAzureCredential
|
||||
mock_credentials = MagicMock()
|
||||
mock_credentials.get_token.return_value = AccessToken(
|
||||
@@ -317,7 +312,6 @@ class TestAzureProvider:
|
||||
"prowler.providers.azure.azure_provider.AzureProvider.validate_static_credentials"
|
||||
) as mock_validate_static_credentials,
|
||||
):
|
||||
|
||||
# Mock the return value of DefaultAzureCredential
|
||||
mock_default_credential.return_value = {
|
||||
"client_id": str(uuid4()),
|
||||
@@ -368,7 +362,6 @@ class TestAzureProvider:
|
||||
"prowler.providers.azure.azure_provider.AzureProvider.validate_static_credentials"
|
||||
) as mock_validate_static_credentials,
|
||||
):
|
||||
|
||||
# Mock the return value of DefaultAzureCredential
|
||||
mock_default_credential.return_value = {
|
||||
"client_id": str(uuid4()),
|
||||
@@ -442,7 +435,6 @@ class TestAzureProvider:
|
||||
"prowler.providers.azure.azure_provider.AzureProvider.setup_session"
|
||||
) as mock_setup_session,
|
||||
):
|
||||
|
||||
mock_setup_session.side_effect = AzureHTTPResponseError(
|
||||
file="test_file", original_exception="Simulated HttpResponseError"
|
||||
)
|
||||
@@ -463,7 +455,6 @@ class TestAzureProvider:
|
||||
with patch(
|
||||
"prowler.providers.azure.azure_provider.AzureProvider.setup_session"
|
||||
) as mock_setup_session:
|
||||
|
||||
mock_setup_session.side_effect = Exception("Simulated Exception")
|
||||
|
||||
with pytest.raises(Exception) as exception:
|
||||
|
||||
+3
@@ -5,6 +5,7 @@ from prowler.providers.azure.services.storage.storage_service import (
|
||||
Account,
|
||||
DeleteRetentionPolicy,
|
||||
FileServiceProperties,
|
||||
SMBProtocolSettings,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
@@ -87,6 +88,7 @@ class Test_storage_ensure_file_shares_soft_delete_is_enabled:
|
||||
name="default",
|
||||
type="Microsoft.Storage/storageAccounts/fileServices",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
smb_protocol_settings=SMBProtocolSettings(channel_encryption=[]),
|
||||
)
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
@@ -145,6 +147,7 @@ class Test_storage_ensure_file_shares_soft_delete_is_enabled:
|
||||
name="default",
|
||||
type="Microsoft.Storage/storageAccounts/fileServices",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
smb_protocol_settings=SMBProtocolSettings(channel_encryption=[]),
|
||||
)
|
||||
storage_client.storage_accounts = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
|
||||
@@ -6,6 +6,7 @@ from prowler.providers.azure.services.storage.storage_service import (
|
||||
DeleteRetentionPolicy,
|
||||
FileServiceProperties,
|
||||
ReplicationSettings,
|
||||
SMBProtocolSettings,
|
||||
Storage,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
@@ -28,6 +29,7 @@ def mock_storage_get_storage_accounts(_):
|
||||
name="name",
|
||||
type="type",
|
||||
share_delete_retention_policy=retention_policy,
|
||||
smb_protocol_settings=SMBProtocolSettings(channel_encryption=[]),
|
||||
)
|
||||
return {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.storage.storage_service import (
|
||||
Account,
|
||||
DeleteRetentionPolicy,
|
||||
FileServiceProperties,
|
||||
SMBProtocolSettings,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_storage_smb_channel_encryption_with_secure_algorithm:
|
||||
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_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm import (
|
||||
storage_smb_channel_encryption_with_secure_algorithm,
|
||||
)
|
||||
|
||||
check = storage_smb_channel_encryption_with_secure_algorithm()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_no_file_service_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_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm import (
|
||||
storage_smb_channel_encryption_with_secure_algorithm,
|
||||
)
|
||||
|
||||
check = storage_smb_channel_encryption_with_secure_algorithm()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_no_smb_protocol_settings(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
file_service_properties = FileServiceProperties(
|
||||
id="id1",
|
||||
name="fs1",
|
||||
type="type1",
|
||||
share_delete_retention_policy=DeleteRetentionPolicy(enabled=True, days=7),
|
||||
smb_protocol_settings=SMBProtocolSettings(channel_encryption=[]),
|
||||
)
|
||||
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=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_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm import (
|
||||
storage_smb_channel_encryption_with_secure_algorithm,
|
||||
)
|
||||
|
||||
check = storage_smb_channel_encryption_with_secure_algorithm()
|
||||
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_SUBSCRIPTION_ID} does not have SMB channel encryption enabled for file shares."
|
||||
)
|
||||
|
||||
def test_not_recommended_encryption(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
file_service_properties = FileServiceProperties(
|
||||
id="id1",
|
||||
name="fs1",
|
||||
type="type1",
|
||||
share_delete_retention_policy=DeleteRetentionPolicy(enabled=True, days=7),
|
||||
smb_protocol_settings=SMBProtocolSettings(
|
||||
channel_encryption=["AES-128-GCM"]
|
||||
),
|
||||
)
|
||||
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=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_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm import (
|
||||
storage_smb_channel_encryption_with_secure_algorithm,
|
||||
)
|
||||
|
||||
check = storage_smb_channel_encryption_with_secure_algorithm()
|
||||
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_SUBSCRIPTION_ID} does not have SMB channel encryption with a secure algorithm for file shares since it supports AES-128-GCM."
|
||||
)
|
||||
|
||||
def test_recommended_encryption(self):
|
||||
storage_account_id = str(uuid4())
|
||||
storage_account_name = "Test Storage Account"
|
||||
file_service_properties = FileServiceProperties(
|
||||
id="id1",
|
||||
name="fs1",
|
||||
type="type1",
|
||||
share_delete_retention_policy=DeleteRetentionPolicy(enabled=True, days=7),
|
||||
smb_protocol_settings=SMBProtocolSettings(
|
||||
channel_encryption=["AES-256-GCM"]
|
||||
),
|
||||
)
|
||||
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=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_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_smb_channel_encryption_with_secure_algorithm.storage_smb_channel_encryption_with_secure_algorithm import (
|
||||
storage_smb_channel_encryption_with_secure_algorithm,
|
||||
)
|
||||
|
||||
check = storage_smb_channel_encryption_with_secure_algorithm()
|
||||
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_SUBSCRIPTION_ID} has a secure algorithm for SMB channel encryption (AES-256-GCM) enabled for file shares since it supports AES-256-GCM."
|
||||
)
|
||||
Reference in New Issue
Block a user