Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Analyze Azure subscriptions to find cost savings via orphaned resources, rightsizing, and usage data
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
cost-optimization/services/storage/azure-storage.md
1## Azure Storage Cost Optimization23Reference guide for identifying cost savings opportunities in Azure Storage accounts through tier analysis, lifecycle policies, and orphaned resource detection.45## Subscription Input Options67Accept any of these identifiers to identify subscriptions for analysis:89| Input Type | Example | Use Case |10|------------|---------|----------|11| **Subscription ID** | `a1b2c3d4-...` | Analyze specific subscription |12| **Subscription Name** | `Production-Environment` | User-friendly identifier |13| **Subscription Prefix** | `StorageTeam -` | Analyze all team subscriptions |14| **Tenant ID** | `tenant-guid` | Analyze entire organization |15| **"All my subscriptions"** | (keyword) | Scan all accessible subscriptions |1617## Cost Optimization Rules1819When analyzing each storage account, apply these prioritized rules:2021| Priority | Rule | Detection Logic | Recommendation | Avg Savings |22|----------|------|----------------|----------------|-------------|23| ๐ด Critical | Orphaned Managed Disks (Compute) | Managed disks with `managedBy` empty (billed as storage) | Delete or snapshot and delete | $20-500/mo |24| ๐ด Critical | Premium in Dev | `sku.name` contains `Premium` AND `tags.environment in ['dev','test','staging']` | Downgrade to Standard | $50-400/mo |25| ๐ High | No Lifecycle Policy | Blob service has no lifecycle management rules configured | Add tiering/deletion rules | $50-300/mo |26| ๐ High | Hot-Only with Infrequent Access | >80% of blobs unaccessed for 30+ days AND all in Hot tier | Move to Cool or enable auto-tiering | $30-200/mo |27| ๐ High | GRS in Non-Production | `sku.name` contains `GRS` or `GZRS` AND `tags.environment in ['dev','test']` | Downgrade to LRS or ZRS | $40-300/mo |28| ๐ High | Classic Storage Accounts | `kind == 'Storage'` (classic/v1) | Upgrade to StorageV2 for tiering support | Variable |29| ๐ก Medium | Large Snapshots | Snapshot cost exceeds 20% of base blob cost | Review snapshot retention policy | $20-100/mo |30| ๐ก Medium | Soft Delete Retention >30 days | `deleteRetentionPolicy.days > 30` | Reduce to 7-14 days unless compliance requires it | $10-50/mo |31| ๐ก Medium | No Access Tier Set | Blobs using default Hot when Cool would suffice | Set explicit Cool or Cold tier | $20-100/mo |32| ๐ก Medium | Unused Containers | Containers with zero blobs or zero access for 90+ days | Delete or archive contents | $5-50/mo |33| ๐ข Low | Untagged Storage Account | Missing required tags (`environment`, `owner`, `costCenter`) | Apply tags for cost allocation | N/A |34| ๐ข Low | Old Storage Account | Age >365 days without review | Verify still needed | Variable |35| ๐ข Low | Version-Heavy Blobs | Blob versioning enabled with >50 versions per blob | Add version deletion lifecycle rule | $5-30/mo |3637## Access Tier Decision Matrix3839| Last Access | Data Size | Access Pattern | Recommended Tier |40|-------------|-----------|----------------|-----------------|41| <30 days | Any | Frequent reads/writes | Hot |42| 30-90 days | Any | Occasional reads | Cool |43| 90-180 days | Any | Rare reads, compliance | Cold |44| >180 days | Any | Archival, legal hold | Archive |4546> **Note**: Archive tier has retrieval costs and rehydration delays (hours). Only use for data that rarely needs access.4748## Lifecycle Policy Template4950Recommend this baseline policy for accounts without lifecycle management:5152```json53{54"rules": [55{56"name": "move-to-cool-after-30-days",57"type": "Lifecycle",58"definition": {59"actions": {60"baseBlob": {61"tierToCool": { "daysAfterLastAccessTimeGreaterThan": 30 }62}63},64"filters": { "blobTypes": ["blockBlob"], "prefixMatch": [] }65}66},67{68"name": "move-to-archive-after-180-days",69"type": "Lifecycle",70"definition": {71"actions": {72"baseBlob": {73"tierToArchive": { "daysAfterLastAccessTimeGreaterThan": 180 }74}75},76"filters": { "blobTypes": ["blockBlob"], "prefixMatch": [] }77}78},79{80"name": "delete-old-snapshots",81"type": "Lifecycle",82"definition": {83"actions": {84"snapshot": {85"delete": { "daysAfterCreationGreaterThan": 90 }86}87},88"filters": { "blobTypes": ["blockBlob"] }89}90},91{92"name": "delete-old-versions",93"type": "Lifecycle",94"definition": {95"actions": {96"version": {97"delete": { "daysAfterCreationGreaterThan": 90 }98}99},100"filters": { "blobTypes": ["blockBlob"] }101}102}103]104}105```106107> โ ๏ธ **Important**: Lifecycle policies that use `daysAfterLastAccessTimeGreaterThan` require **last access time tracking** to be enabled on the storage account. Verify with: `az storage account blob-service-properties show --account-name <name> --resource-group <rg> --query lastAccessTimeTrackingPolicy`108109## Resource Graph Queries110111**Find storage accounts without lifecycle policies:**112113Use Azure CLI to check lifecycle policy presence (not queryable via Resource Graph):114115```bash116az storage account management-policy show --account-name <name> --resource-group <rg>117```118119**Find Premium storage accounts in non-production:**120121```kql122Resources123| where type =~ 'microsoft.storage/storageaccounts'124| where sku.name contains 'Premium'125| where tags.environment in~ ('dev', 'test', 'staging', 'sandbox')126| project name, resourceGroup, sku=sku.name, tags127```128129**Find GRS/GZRS accounts in dev/test (redundancy downgrade candidates):**130131```kql132Resources133| where type =~ 'microsoft.storage/storageaccounts'134| where sku.name contains 'GRS' or sku.name contains 'GZRS'135| where tags.environment in~ ('dev', 'test', 'staging')136| project name, resourceGroup, sku=sku.name, location, tags137```138139**Find classic (v1) storage accounts:**140141```kql142Resources143| where type =~ 'microsoft.storage/storageaccounts'144| where kind =~ 'Storage'145| project name, resourceGroup, location, kind146```147148**Find orphaned managed disks (unattached):**149150```kql151Resources152| where type =~ 'microsoft.compute/disks'153| where isempty(managedBy)154| project name, resourceGroup, location, diskSizeGb=properties.diskSizeGB, sku=sku.name155```156157## Report Templates158159### Subscription-Level Summary160Include: subscription name/ID, total monthly storage cost, account count by SKU/tier, total data stored (TB), top issues found.161162### Detailed Storage Account Analysis163Include: account name, resource group, SKU/redundancy, kind, monthly cost, capacity (GB), access tier distribution (%), lifecycle policy status, and optimization recommendations.164165## Tools & Commands166167**MCP Tool:** `azure__storage` with sub-commands for account and container operations168169**Azure CLI:**170- `az storage account list --subscription <id>` - List accounts171- `az storage account show --name <name> --resource-group <rg>` - Get details172- `az storage account management-policy show --account-name <name> --resource-group <rg>` - Check lifecycle policy173- `az storage account blob-service-properties show --account-name <name> --resource-group <rg> --query lastAccessTimeTrackingPolicy` - Check access tracking174- `az monitor metrics list --resource <id> --metric UsedCapacity` - Capacity metrics175- `az monitor metrics list --resource <id> --metric Transactions --dimension ApiName` - Access patterns176177## Pricing Quick Reference178179Tiers ranked by storage cost (East US, LRS, approximate):180- **Hot**: $0.018/GB/mo (cheapest reads)181- **Cool**: $0.01/GB/mo (30-day minimum retention)182- **Cold**: $0.0036/GB/mo (90-day minimum)183- **Archive**: $0.002/GB/mo (180-day minimum, hours to rehydrate)184185Always validate from [official pricing](https://azure.microsoft.com/pricing/details/storage/blobs/).186187**Redundancy savings**: Downgrading from GRS to LRS saves ~50%. Dev/test rarely needs GRS/GZRS.188