Azure waste

Hot-tier blob data that nothing has touched

Blob data held in the Hot access tier on an account that recorded no transactions at all over the window, where the Cool tier would bill less for the same bytes.
The agent reports this
Why it happens

Hot-tier blob capacity bills at a higher per-GB rate than Cool in exchange for cheaper access, so data nobody reads is paying for an access discount it never uses. The rule fires only when transactions across the window are exactly zero, because the trade runs the other way as soon as the data is read: on LRS the Hot-to-Cool saving is about $0.0056 per GB per month while reading a GB back from Cool costs about $0.01, so a single full read a month makes Cool the more expensive tier. Zero transactions is the one condition under which the saving is real rather than a bet on future access. Premium block blob accounts are excluded because Azure publishes no Cool capacity meter for them, so there is nothing to move to.

Paste this into Resource Graph Explorer in the Azure portal.

resources
| where type =~ 'microsoft.storage/storageaccounts'
// Scope below matches CloudFinOpsPro policy DEFAULTS: exclusions.protectTag, environment.tagKeys,
// environment.allowedTagValues, and allowUntagged false so an untagged resource counts as production.
// If your policy.yaml differs, edit the three lines below or this will disagree with your own agent.
| where tolower(tostring(coalesce(tags['cfop:protect'], ''))) !in ('true', 'yes', '1')
| extend cfopEnv = tolower(trim(' ', tostring(coalesce(tags['Environment'], tags['environment'], tags['env'], ''))))
| where cfopEnv in ('dev', 'development', 'test', 'qa', 'sandbox', 'nonprod', 'non-prod', 'staging')
| where tostring(properties.accessTier) =~ 'Hot'
| project account = name, resourceGroup, location,
          sku = tostring(sku.name),
          acctKind = tostring(kind)

Resource Graph shows the account's default tier, not the tier of each blob, and it cannot show when a blob was last read. The lifecycle management policy is deliberately not projected: it is a sub-resource that the accounts row does not carry, so isnotnull(properties.managementPolicy) reads false on every account and would suggest no rules exist when it only means Resource Graph cannot see them. Confirm with the Azure Monitor BlobCapacity metric split by BlobTier before moving anything, because reading data back from Cool or Archive carries a retrieval charge that can exceed the saving.

Applies to microsoft.storage/storageaccounts
What the agent does about it

Blob data held in the Hot access tier on an account that recorded no transactions at all over the window, where the Cool tier would bill less for the same bytes.

It will not fix this one

It reports this and takes no action. A check only earns the right to change something once the action behind it can re-read live state before it fires and knows the way back.