turbot/steampipe-mod-azure-compliance

Control: 9.3.1.2 Ensure that Storage Account access keys are periodically regenerated

Description

For increased security, regenerate storage account access keys periodically.

When a storage account is created, Azure generates two 512-bit storage access keys which are used for authentication when the storage account is accessed. Rotating these keys periodically ensures that any inadvertent access or exposure does not result from the compromise of these keys.

Cryptographic key rotation periods will vary depending on your organization's security requirements and the type of data which is being stored in the Storage Account. For example, PCI DSS mandates that cryptographic keys be replaced or rotated 'regularly,' and advises that keys for static data stores be rotated every 'few months.'

For the purposes of this recommendation, 90 days will be prescribed for the reminder. Review and adjustment of the 90 day period is recommended, and may even be necessary. Your organization's security requirements should dictate the appropriate setting.

Remediation

Remediate from Azure Portal

  1. Go to Storage Accounts.
  2. For each Storage Account with outdated keys, under Security + networking, go to Access keys.
  3. Click Rotate key next to the outdated key, then click Yes to the prompt confirming that you want to regenerate the access key.

After Azure regenerates the Access Key, you can confirm that Access keys reflects a Last rotated date of (0 days ago).

Default Value

By default, access keys are not regenerated periodically.

Usage

Run the control in your terminal:

powerpipe control run azure_compliance.control.cis_v500_9_3_1_2

Snapshot and share results via Turbot Pipes:

powerpipe login
powerpipe control run azure_compliance.control.cis_v500_9_3_1_2 --share

SQL

This control uses a named query:

with storage_account_key_status as (
select
sa.id,
sa.name as storage_account_name,
sa.subscription_id,
sa._ctx,
sa.region,
sa.resource_group,
sa.tags,
key ->> 'KeyName' as key_name,
(key ->> 'CreationTime')::timestamptz as last_rotated,
extract(
epoch
from (now() - (key ->> 'CreationTime')::timestamptz)
) / 86400 as days_since_rotation
from
azure_storage_account as sa
left join lateral jsonb_array_elements(sa.access_keys) as key on true
)
select
saks.id as resource,
case
when saks.key_name is null then 'skip'
when saks.days_since_rotation > 90 then 'alarm'
else 'ok'
end as status,
case
when saks.key_name is null then saks.storage_account_name || ' has no access keys available.'
else saks.storage_account_name || ' ' || saks.key_name || ' last rotated ' || floor(saks.days_since_rotation)::int || ' days ago.'
end as reason
, saks.resource_group as resource_group
, sub.display_name as subscription
from
storage_account_key_status saks
left join azure_subscription sub on sub.subscription_id = saks.subscription_id;

Tags