feat(azure): Add new check storage_key_rotation_90_days (#3323)

This commit is contained in:
Pedro Martín
2024-01-29 12:57:19 +01:00
committed by GitHub
parent a8edd03e65
commit ae1ab1d957
13 changed files with 238 additions and 2 deletions

View File

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

View File

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

View File

@@ -31,12 +31,12 @@ 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,
key_expiration_period_in_days=storage_account.key_policy.key_expiration_period_in_days,
)
)
except Exception as error:
logger.error(f"Subscription name: {subscription}")
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
@@ -51,3 +51,4 @@ class Storage_Account:
network_rule_set: NetworkRuleSet
encryption_type: str
minimum_tls_version: str
key_expiration_period_in_days: str

View File

@@ -40,6 +40,13 @@ expected_packages = [
name="prowler.providers.azure.services.storage.storage_ensure_minimum_tls_version_12.storage_ensure_minimum_tls_version_12",
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(
module_finder=FileFinder("/root_dir/prowler/providers/azure/services/storage"),
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",
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(
module_finder=FileFinder(
"/root_dir/prowler/providers/azure/services/storage"
@@ -447,6 +461,10 @@ class Test_Check:
"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",
"/root_dir/prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys",

View File

@@ -38,6 +38,7 @@ class Test_storage_blob_public_access_level_is_disabled:
network_rule_set=None,
encryption_type=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,
encryption_type=None,
minimum_tls_version=None,
key_expiration_period_in_days=None,
)
]
}

View File

@@ -40,6 +40,7 @@ class Test_storage_default_network_access_rule_is_denied:
network_rule_set=NetworkRuleSet(default_action="Allow"),
encryption_type=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"),
encryption_type=None,
minimum_tls_version=None,
key_expiration_period_in_days=None,
)
]
}

View File

@@ -40,6 +40,7 @@ class Test_storage_ensure_azure_services_are_trusted_to_access_is_enabled:
network_rule_set=NetworkRuleSet(bypass=[None]),
encryption_type=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"]),
encryption_type=None,
minimum_tls_version=None,
key_expiration_period_in_days=None,
)
]
}

View File

@@ -38,6 +38,7 @@ class Test_storage_ensure_encryption_with_customer_managed_keys:
network_rule_set=None,
encryption_type="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,
encryption_type="Microsoft.Keyvault",
minimum_tls_version=None,
key_expiration_period_in_days=None,
)
]
}

View File

@@ -38,6 +38,7 @@ class Test_storage_ensure_minimum_tls_version_12:
network_rule_set=None,
encryption_type="None",
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,
encryption_type="None",
minimum_tls_version="TLS1_2",
key_expiration_period_in_days=None,
)
]
}

View File

@@ -38,6 +38,7 @@ class Test_storage_infrastructure_encryption_is_enabled:
network_rule_set=None,
encryption_type="None",
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,
encryption_type="None",
minimum_tls_version="TLS1_1",
key_expiration_period_in_days=None,
)
]
}

View File

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

View File

@@ -38,6 +38,7 @@ class Test_storage_secure_transfer_required_is_enabled:
network_rule_set=None,
encryption_type="None",
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,
encryption_type="None",
minimum_tls_version="TLS1_1",
key_expiration_period_in_days=None,
)
]
}