Storage account has access key expiration period set to 90 days or less
Azure Storage accounts must define a key expiration period for access-key rotation, with a maximum of 90 days. The evaluation looks for accounts lacking this setting or exceeding that limit.
Risk
Long-lived storage access keys undermine confidentiality and integrity: a leaked or reused key grants full data access and can sign SAS tokens. Extended validity enables persistent unauthorized access, data exfiltration, and tampering, and complicates revocation and incident response.
Run this check with Prowler
Run in Prowler Cloudprowler azure --checks storage_key_rotation_90_daysRecommendation
Enforce a key expiration period of <= 90 days and automate rotation. Prefer Microsoft Entra ID with managed identities over Shared Key; when SAS is needed, use user-delegation SAS. Apply least privilege, minimize key distribution, monitor usage, rotate on suspected exposure, and disable Shared Key when feasible.
Remediation
CLI
az storage account update --name <STORAGE_ACCOUNT_NAME> --resource-group <RESOURCE_GROUP_NAME> --key-exp-days 90Terraform
resource "azurerm_storage_account" "<example_resource_name>" {
name = "<example_resource_name>"
resource_group_name = "<example_resource_name>"
location = "<example_resource_name>"
account_tier = "Standard"
account_replication_type = "LRS"
key_policy {
key_expiration_period_in_days = 90 # CRITICAL: sets key expiration period to 90 days to pass the check
}
}NativeIaC
// Set key expiration period to 90 days or less
resource stg 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: '<example_resource_name>'
location: resourceGroup().location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
properties: {
keyPolicy: {
keyExpirationPeriodInDays: 90 // CRITICAL: enforces rotation reminder at 90 days to pass the check
}
}
}Other
Check Code
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():
subscription_name = storage_client.subscriptions.get(
subscription, subscription
)
for storage_account in storage_accounts:
report = Check_Report_Azure(
metadata=self.metadata(), resource=storage_account
)
report.subscription = subscription
if not storage_account.key_expiration_period_in_days:
report.status = "FAIL"
report.status_extended = f"Storage account {storage_account.name} from subscription {subscription_name} ({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_name} ({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_name} ({subscription}) has a key expiration period of {storage_account.key_expiration_period_in_days} days."
findings.append(report)
return findingsReferences
- https://learn.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal
- https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal#regenerate-storage-access-keys
- https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/StorageAccounts/regenerate-storage-account-access-keys-periodically.html#