mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(azure): Add new check storage_key_rotation_90_days (#3323)
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"Provider": "azure",
|
||||||
|
"CheckID": "storage_key_rotation_90_days",
|
||||||
|
"CheckTitle": "Ensure that Storage Account Access Keys are Periodically Regenerated",
|
||||||
|
"CheckType": [],
|
||||||
|
"ServiceName": "storage",
|
||||||
|
"SubServiceName": "",
|
||||||
|
"ResourceIdTemplate": "",
|
||||||
|
"Severity": "medium",
|
||||||
|
"ResourceType": "AzureStorageAccount",
|
||||||
|
"Description": "Ensure that Storage Account Access Keys are Periodically Regenerated",
|
||||||
|
"Risk": "If the access keys are not regenerated periodically, the likelihood of accidental exposures increases, which can lead to unauthorized access to your storage account resources.",
|
||||||
|
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal",
|
||||||
|
"Remediation": {
|
||||||
|
"Code": {
|
||||||
|
"CLI": "",
|
||||||
|
"NativeIaC": "",
|
||||||
|
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/StorageAccounts/regenerate-storage-account-access-keys-periodically.html#",
|
||||||
|
"Terraform": ""
|
||||||
|
},
|
||||||
|
"Recommendation": {
|
||||||
|
"Text": "Ensure that Azure Storage account access keys are regenerated every 90 days in order to decrease the likelihood of accidental exposures and protect your storage account resources against unauthorized access.",
|
||||||
|
"Url": "https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal#regenerate-storage-access-keys"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Categories": [
|
||||||
|
"encryption"
|
||||||
|
],
|
||||||
|
"DependsOn": [],
|
||||||
|
"RelatedTo": [],
|
||||||
|
"Notes": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||||
|
from prowler.providers.azure.services.storage.storage_client import storage_client
|
||||||
|
|
||||||
|
|
||||||
|
class storage_key_rotation_90_days(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 not storage_account.key_expiration_period_in_days:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has no key expiration period set."
|
||||||
|
else:
|
||||||
|
if storage_account.key_expiration_period_in_days > 90:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has an invalid key expiration period of {storage_account.key_expiration_period_in_days} days."
|
||||||
|
else:
|
||||||
|
report.status = "PASS"
|
||||||
|
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription} has a key expiration period of {storage_account.key_expiration_period_in_days} days."
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
|
return findings
|
||||||
@@ -31,12 +31,12 @@ class Storage(AzureService):
|
|||||||
network_rule_set=storage_account.network_rule_set,
|
network_rule_set=storage_account.network_rule_set,
|
||||||
encryption_type=storage_account.encryption.key_source,
|
encryption_type=storage_account.encryption.key_source,
|
||||||
minimum_tls_version=storage_account.minimum_tls_version,
|
minimum_tls_version=storage_account.minimum_tls_version,
|
||||||
|
key_expiration_period_in_days=storage_account.key_policy.key_expiration_period_in_days,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(f"Subscription name: {subscription}")
|
|
||||||
logger.error(
|
logger.error(
|
||||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
)
|
)
|
||||||
return storage_accounts
|
return storage_accounts
|
||||||
|
|
||||||
@@ -51,3 +51,4 @@ class Storage_Account:
|
|||||||
network_rule_set: NetworkRuleSet
|
network_rule_set: NetworkRuleSet
|
||||||
encryption_type: str
|
encryption_type: str
|
||||||
minimum_tls_version: str
|
minimum_tls_version: str
|
||||||
|
key_expiration_period_in_days: str
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ expected_packages = [
|
|||||||
name="prowler.providers.azure.services.storage.storage_ensure_minimum_tls_version_12.storage_ensure_minimum_tls_version_12",
|
name="prowler.providers.azure.services.storage.storage_ensure_minimum_tls_version_12.storage_ensure_minimum_tls_version_12",
|
||||||
ispkg=False,
|
ispkg=False,
|
||||||
),
|
),
|
||||||
|
ModuleInfo(
|
||||||
|
module_finder=FileFinder(
|
||||||
|
"/root_dir/prowler/providers/azure/services/storage/storage_key_rotation_90_days"
|
||||||
|
),
|
||||||
|
name="prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days",
|
||||||
|
ispkg=False,
|
||||||
|
),
|
||||||
ModuleInfo(
|
ModuleInfo(
|
||||||
module_finder=FileFinder("/root_dir/prowler/providers/azure/services/storage"),
|
module_finder=FileFinder("/root_dir/prowler/providers/azure/services/storage"),
|
||||||
name="prowler.providers.azure.services.storage.storage_ensure_encryption_with_customer_managed_keys",
|
name="prowler.providers.azure.services.storage.storage_ensure_encryption_with_customer_managed_keys",
|
||||||
@@ -68,6 +75,13 @@ def mock_list_modules(*_):
|
|||||||
name="prowler.providers.azure.services.storage.storage_ensure_minimum_tls_version_12.storage_ensure_minimum_tls_version_12",
|
name="prowler.providers.azure.services.storage.storage_ensure_minimum_tls_version_12.storage_ensure_minimum_tls_version_12",
|
||||||
ispkg=False,
|
ispkg=False,
|
||||||
),
|
),
|
||||||
|
ModuleInfo(
|
||||||
|
module_finder=FileFinder(
|
||||||
|
"/root_dir/prowler/providers/azure/services/storage/storage_key_rotation_90_days"
|
||||||
|
),
|
||||||
|
name="prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days",
|
||||||
|
ispkg=False,
|
||||||
|
),
|
||||||
ModuleInfo(
|
ModuleInfo(
|
||||||
module_finder=FileFinder(
|
module_finder=FileFinder(
|
||||||
"/root_dir/prowler/providers/azure/services/storage"
|
"/root_dir/prowler/providers/azure/services/storage"
|
||||||
@@ -447,6 +461,10 @@ class Test_Check:
|
|||||||
"storage_ensure_minimum_tls_version_12",
|
"storage_ensure_minimum_tls_version_12",
|
||||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_minimum_tls_version_12",
|
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_minimum_tls_version_12",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"storage_key_rotation_90_days",
|
||||||
|
"/root_dir/prowler/providers/azure/services/storage/storage_key_rotation_90_days",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"storage_ensure_encryption_with_customer_managed_keys",
|
"storage_ensure_encryption_with_customer_managed_keys",
|
||||||
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys",
|
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Test_storage_blob_public_access_level_is_disabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ class Test_storage_blob_public_access_level_is_disabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class Test_storage_default_network_access_rule_is_denied:
|
|||||||
network_rule_set=NetworkRuleSet(default_action="Allow"),
|
network_rule_set=NetworkRuleSet(default_action="Allow"),
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -79,6 +80,7 @@ class Test_storage_default_network_access_rule_is_denied:
|
|||||||
network_rule_set=NetworkRuleSet(default_action="Deny"),
|
network_rule_set=NetworkRuleSet(default_action="Deny"),
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled:
|
|||||||
network_rule_set=NetworkRuleSet(bypass=[None]),
|
network_rule_set=NetworkRuleSet(bypass=[None]),
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -79,6 +80,7 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled:
|
|||||||
network_rule_set=NetworkRuleSet(bypass=["AzureServices"]),
|
network_rule_set=NetworkRuleSet(bypass=["AzureServices"]),
|
||||||
encryption_type=None,
|
encryption_type=None,
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Test_storage_ensure_encryption_with_customer_managed_keys:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ class Test_storage_ensure_encryption_with_customer_managed_keys:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="Microsoft.Keyvault",
|
encryption_type="Microsoft.Keyvault",
|
||||||
minimum_tls_version=None,
|
minimum_tls_version=None,
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Test_storage_ensure_minimum_tls_version_12:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_1",
|
minimum_tls_version="TLS1_1",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ class Test_storage_ensure_minimum_tls_version_12:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_2",
|
minimum_tls_version="TLS1_2",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Test_storage_infrastructure_encryption_is_enabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_1",
|
minimum_tls_version="TLS1_1",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ class Test_storage_infrastructure_encryption_is_enabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_1",
|
minimum_tls_version="TLS1_1",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
from unittest import mock
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from prowler.providers.azure.services.storage.storage_service import Storage_Account
|
||||||
|
from tests.providers.azure.azure_fixtures import AZURE_SUSCRIPTION
|
||||||
|
|
||||||
|
|
||||||
|
class Test_storage_key_rotation_90_dayss:
|
||||||
|
def test_storage_no_storage_accounts(self):
|
||||||
|
storage_client = mock.MagicMock
|
||||||
|
storage_client.storage_accounts = {}
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days.storage_client",
|
||||||
|
new=storage_client,
|
||||||
|
):
|
||||||
|
from prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days import (
|
||||||
|
storage_key_rotation_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = storage_key_rotation_90_days()
|
||||||
|
result = check.execute()
|
||||||
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_storage_storage_key_rotation_91_days(self):
|
||||||
|
storage_account_id = str(uuid4())
|
||||||
|
storage_account_name = "Test Storage Account"
|
||||||
|
expiration_days = 91
|
||||||
|
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="TLS1_1",
|
||||||
|
key_expiration_period_in_days=expiration_days,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days.storage_client",
|
||||||
|
new=storage_client,
|
||||||
|
):
|
||||||
|
from prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days import (
|
||||||
|
storage_key_rotation_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = storage_key_rotation_90_days()
|
||||||
|
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} has an invalid key expiration period of {expiration_days} days."
|
||||||
|
)
|
||||||
|
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_storage_key_rotation_90_days(self):
|
||||||
|
storage_account_id = str(uuid4())
|
||||||
|
storage_account_name = "Test Storage Account"
|
||||||
|
expiration_days = 90
|
||||||
|
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="TLS1_2",
|
||||||
|
key_expiration_period_in_days=expiration_days,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days.storage_client",
|
||||||
|
new=storage_client,
|
||||||
|
):
|
||||||
|
from prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days import (
|
||||||
|
storage_key_rotation_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = storage_key_rotation_90_days()
|
||||||
|
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 a key expiration period of {expiration_days} days."
|
||||||
|
)
|
||||||
|
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_storage_no_key_rotation(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="TLS1_2",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
"prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days.storage_client",
|
||||||
|
new=storage_client,
|
||||||
|
):
|
||||||
|
from prowler.providers.azure.services.storage.storage_key_rotation_90_days.storage_key_rotation_90_days import (
|
||||||
|
storage_key_rotation_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = storage_key_rotation_90_days()
|
||||||
|
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} has no key expiration period set."
|
||||||
|
)
|
||||||
|
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||||
|
assert result[0].resource_name == storage_account_name
|
||||||
|
assert result[0].resource_id == storage_account_id
|
||||||
@@ -38,6 +38,7 @@ class Test_storage_secure_transfer_required_is_enabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_1",
|
minimum_tls_version="TLS1_1",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ class Test_storage_secure_transfer_required_is_enabled:
|
|||||||
network_rule_set=None,
|
network_rule_set=None,
|
||||||
encryption_type="None",
|
encryption_type="None",
|
||||||
minimum_tls_version="TLS1_1",
|
minimum_tls_version="TLS1_1",
|
||||||
|
key_expiration_period_in_days=None,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user