mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(storage): add new check storage_cross_tenant_replication_disabled (#7977)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
cc8f6131e6
commit
1b73ab2fe4
@@ -5,6 +5,8 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
## [v5.8.0] (Prowler UNRELEASED)
|
||||
|
||||
### Added
|
||||
|
||||
- Add `storage_cross_tenant_replication_disabled` check for Azure provider. [(#7977)](https://github.com/prowler-cloud/prowler/pull/7977)
|
||||
- CIS 1.11 compliance framework for Kubernetes [(#7790)](https://github.com/prowler-cloud/prowler/pull/7790)
|
||||
- Support `HTTPS_PROXY` and `K8S_SKIP_TLS_VERIFY` in Kubernetes [(#7720)](https://github.com/prowler-cloud/prowler/pull/7720)
|
||||
- Weight for Prowler ThreatScore scoring [(#7795)](https://github.com/prowler-cloud/prowler/pull/7795)
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "storage_cross_tenant_replication_disabled",
|
||||
"CheckTitle": "Ensure cross-tenant replication is disabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "storage",
|
||||
"SubServiceName": "account",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "AzureStorageAccount",
|
||||
"Description": "Ensure that cross-tenant replication is not enabled on Azure Storage Accounts to prevent unintended replication of data across tenant boundaries.",
|
||||
"Risk": "If cross-tenant replication is enabled, sensitive data could be inadvertently replicated across tenants, increasing the risk of data leakage, unauthorized access, or non-compliance with data governance and privacy policies.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/storage/blobs/object-replication-prevent-cross-tenant-policies?tabs=portal",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az storage account update --name <storage-account-name> --resource-group <resource-group> --default-to-oauth-authentication true --allow-cross-tenant-replication false",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/StorageAccounts/disable-cross-tenant-replication.html",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Disable Cross Tenant Replication on storage accounts to ensure that data remains within tenant boundaries unless explicitly shared, reducing the risk of data leakage and unauthorized access.",
|
||||
"Url": "https://learn.microsoft.com/en-us/azure/storage/blobs/object-replication-prevent-cross-tenant-policies?tabs=portal"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.storage.storage_client import storage_client
|
||||
|
||||
|
||||
class storage_cross_tenant_replication_disabled(Check):
|
||||
"""Check if cross-tenant replication is disabled.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
"""Execute the check for cross-tenant replication.
|
||||
|
||||
This method checks if cross-tenant replication is disabled. If it is, the check passes; otherwise, it fails.
|
||||
|
||||
Returns:
|
||||
Check_Report_Azure: A report containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for subscription, storage_accounts in storage_client.storage_accounts.items():
|
||||
for storage_account in storage_accounts:
|
||||
report = Check_Report_Azure(
|
||||
metadata=self.metadata(), resource=storage_account
|
||||
)
|
||||
report.subscription = subscription
|
||||
if not storage_account.allow_cross_tenant_replication:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has cross-tenant replication disabled."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has cross-tenant replication enabled."
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -68,6 +68,9 @@ class Storage(AzureService):
|
||||
],
|
||||
key_expiration_period_in_days=key_expiration_period_in_days,
|
||||
location=storage_account.location,
|
||||
allow_cross_tenant_replication=getattr(
|
||||
storage_account, "allow_cross_tenant_replication", True
|
||||
),
|
||||
allow_shared_key_access=getattr(
|
||||
storage_account, "allow_shared_key_access", True
|
||||
),
|
||||
@@ -222,6 +225,7 @@ class Account:
|
||||
private_endpoint_connections: List[PrivateEndpointConnection]
|
||||
key_expiration_period_in_days: str
|
||||
location: str
|
||||
allow_cross_tenant_replication: bool = True
|
||||
allow_shared_key_access: bool = True
|
||||
blob_properties: Optional[BlobProperties] = None
|
||||
file_shares: list = None
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.storage.storage_service import Account
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_storage_cross_tenant_replication_disabled:
|
||||
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_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled import (
|
||||
storage_cross_tenant_replication_disabled,
|
||||
)
|
||||
|
||||
check = storage_cross_tenant_replication_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_storage_account_cross_tenant_replication_enabled(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,
|
||||
allow_cross_tenant_replication=True,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
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_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled import (
|
||||
storage_cross_tenant_replication_disabled,
|
||||
)
|
||||
|
||||
check = storage_cross_tenant_replication_disabled()
|
||||
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} has cross-tenant replication enabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == storage_account_id
|
||||
assert result[0].location == "westeurope"
|
||||
|
||||
def test_storage_account_cross_tenant_replication_disabled(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,
|
||||
allow_cross_tenant_replication=False,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
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_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled.storage_client",
|
||||
new=storage_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.storage.storage_cross_tenant_replication_disabled.storage_cross_tenant_replication_disabled import (
|
||||
storage_cross_tenant_replication_disabled,
|
||||
)
|
||||
|
||||
check = storage_cross_tenant_replication_disabled()
|
||||
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 cross-tenant replication disabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == storage_account_name
|
||||
assert result[0].resource_id == storage_account_id
|
||||
assert result[0].location == "westeurope"
|
||||
@@ -40,6 +40,7 @@ def mock_storage_get_storage_accounts(_):
|
||||
private_endpoint_connections=None,
|
||||
location="westeurope",
|
||||
blob_properties=blob_properties,
|
||||
allow_cross_tenant_replication=True,
|
||||
allow_shared_key_access=True,
|
||||
file_shares=file_shares,
|
||||
)
|
||||
@@ -117,6 +118,12 @@ class Test_Storage_Service:
|
||||
default_service_version=None,
|
||||
container_delete_retention_policy=None,
|
||||
)
|
||||
assert (
|
||||
storage.storage_accounts[AZURE_SUBSCRIPTION_ID][
|
||||
0
|
||||
].allow_cross_tenant_replication
|
||||
is True
|
||||
)
|
||||
assert (
|
||||
storage.storage_accounts[AZURE_SUBSCRIPTION_ID][0].allow_shared_key_access
|
||||
is True
|
||||
|
||||
Reference in New Issue
Block a user