Azure Provider
Deep dive into scanning Azure resources with Cloud Cost Analyzer.
Supported Services
CCA discovers the following Azure resources. Optimization rules currently target virtual machines; the other resource types are collected for inventory and reporting, with cost rules planned.
| Service | Resource Types | Optimization Rules |
|---|---|---|
| Virtual Machines | VMs | Rightsizing, Reserved Instance coverage, Hybrid Benefit |
| Managed Disks | Disks | Discovery only (rules planned) |
| Storage Accounts | Blob, File, Table | Discovery only (rules planned) |
| SQL Database | Databases | Discovery only (rules planned) |
| Load Balancers | Standard, Basic | Discovery only |
| Public IPs | Static, Dynamic | Discovery only |
| Network Interfaces | NICs | Discovery only |
Authentication
CCA supports multiple Azure authentication methods:
Azure CLI (Recommended for Development)
# Login interactively
az login
# Set subscription
az account set --subscription "My Subscription"
# Run scan
cca scan --provider azure
Service Principal (Recommended for CI/CD)
Create a service principal:
# Create service principal with Reader role
az ad sp create-for-rbac \
--name "CloudCostAnalyzer" \
--role Reader \
--scopes /subscriptions/YOUR_SUBSCRIPTION_ID
Output:
{
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "CloudCostAnalyzer",
"password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Configure environment variables:
export AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_SUBSCRIPTION_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
cca scan --provider azure
Managed Identity (Azure VMs, App Service, Functions)
For resources running in Azure, use managed identity:
# No configuration needed - credentials are retrieved automatically
cca scan --provider azure
Enable managed identity on your resource:
# Enable system-assigned managed identity on a VM
az vm identity assign --resource-group myRG --name myVM
# Grant Reader access to the subscription
az role assignment create \
--assignee <principal-id> \
--role Reader \
--scope /subscriptions/YOUR_SUBSCRIPTION_ID
Workload Identity (AKS)
For AKS clusters using workload identity:
# Pod configuration
apiVersion: v1
kind: Pod
metadata:
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: cca-service-account
containers:
- name: cca
image: dragonfractal/cca:latest
Provisioning access
cca setup --provider azure provisions the read-only access a scan needs (a
service principal with Reader + Cost Management Reader). Who runs it
depends on your environment.
Self-service (you can register apps and assign roles)
cca setup --provider azure --output-template # preview the roles + az commands
AZURE_SUBSCRIPTION_ID=<sub> cca setup --provider azure --deploy
--deploy is idempotent: re-running keeps the existing service principal and
re-ensures its roles; add --rotate-secret to mint a new secret. Running it
requires:
- rights to create a service principal: the Application Developer directory role (which allows app registration even when the tenant-wide setting is off), or the tenant setting Users can register applications = Yes; and
- rights to assign roles on the subscription: Owner or User Access Administrator.
Restricted (you cannot register apps or assign roles)
Common in locked-down tenants. Hand off instead:
cca setup --provider azure --output-template -f cca-azure-setup.sh
Give the script to your platform team, or have an admin run it. You then consume
the resulting AZURE_* credentials, or use workload identity federation for
CI, with no secrets (see the GitHub Actions guide).
Required Permissions
CCA requires the Reader role at the subscription level:
# Assign Reader role to service principal
az role assignment create \
--assignee $AZURE_CLIENT_ID \
--role Reader \
--scope /subscriptions/$AZURE_SUBSCRIPTION_ID
For cost data access, also assign Cost Management Reader:
az role assignment create \
--assignee $AZURE_CLIENT_ID \
--role "Cost Management Reader" \
--scope /subscriptions/$AZURE_SUBSCRIPTION_ID
Custom Role (Minimal Permissions)
Create a custom role with minimal permissions:
{
"Name": "CCA Reader",
"Description": "Read-only access for Cloud Cost Analyzer",
"Actions": [
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/disks/read",
"Microsoft.Storage/storageAccounts/read",
"Microsoft.Sql/servers/read",
"Microsoft.Sql/servers/databases/read",
"Microsoft.Web/sites/read",
"Microsoft.Web/serverfarms/read",
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.Network/loadBalancers/read",
"Microsoft.Cache/redis/read",
"Microsoft.DocumentDB/databaseAccounts/read",
"Microsoft.Insights/metrics/read",
"Microsoft.CostManagement/query/read",
"Microsoft.Resources/subscriptions/resourceGroups/read"
],
"NotActions": [],
"AssignableScopes": [
"/subscriptions/YOUR_SUBSCRIPTION_ID"
]
}
Deploy:
az role definition create --role-definition cca-role.json
az role assignment create \
--assignee $AZURE_CLIENT_ID \
--role "CCA Reader" \
--scope /subscriptions/$AZURE_SUBSCRIPTION_ID
Scanning Options
Subscription Selection
The subscription comes from the standard Azure environment variable: there is no --subscription flag:
export AZURE_SUBSCRIPTION_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
cca scan --provider azure
Filtering
# Limit to specific service categories (comma-separated):
# compute, storage, database, networking, serverless, analytics,
# containers, ai, security, monitoring, cdn, other
cca scan --provider azure --services compute,storage
# Keep only findings on resources tagged Environment=production
# (repeat --tags for AND semantics; all must match)
cca scan --provider azure --tags Environment=production
Azure-Specific Rules
VM Rightsizing
Identifies VMs with low CPU/memory utilization:
Rule ID: azure-vm-rightsizing
Severity: High
Triggers when:
- Average CPU < 10% over 14 days
- Or max CPU < 40% over 14 days
Example finding:
{
"rule_id": "azure-vm-rightsizing",
"resource_id": "/subscriptions/.../virtualMachines/myVM",
"title": "VM oversized",
"recommendation": "Consider downsizing from Standard_D4s_v3 to Standard_D2s_v3",
"estimated_monthly_savings": 145.00,
"metadata": {
"current_size": "Standard_D4s_v3",
"recommended_size": "Standard_D2s_v3",
"avg_cpu_percent": 8.2
}
}
Reserved Instance Opportunities
Flags on-demand VMs that would be cheaper under a reservation:
Rule ID: azure-reserved-instances
Severity: High
Triggers when: VM running steadily with no reservation coverage
Azure Hybrid Benefit
Flags Windows/SQL VMs eligible for Hybrid Benefit licensing savings:
Rule ID: azure-hybrid-benefit
Severity: Medium
Triggers when: Eligible VM not using existing on-premises licenses
Disk, storage-account, and SQL optimization rules are planned. Those resources are discovered and inventoried today, but no cost rules run against them yet.
Multi-Subscription Scanning
List Subscriptions
# List accessible subscriptions
az account list --query '[].{Name:name, ID:id}' --output table
Scan All Subscriptions
# Get all subscription IDs
subscriptions=$(az account list --query '[].id' --output tsv)
# Scan each subscription (set it via the Azure env var)
for sub in $subscriptions; do
echo "Scanning subscription: $sub"
AZURE_SUBSCRIPTION_ID=$sub cca scan --provider azure
done
Management Group Scope
For organizations using management groups:
# List management groups
az account management-group list
# Grant access at management group level
az role assignment create \
--assignee $AZURE_CLIENT_ID \
--role Reader \
--scope /providers/Microsoft.Management/managementGroups/YOUR_MG_ID
Troubleshooting
"Authorization Failed" Errors
Check role assignments:
# List role assignments for service principal
az role assignment list --assignee $AZURE_CLIENT_ID --output table
# Verify subscription access
az account show --subscription $AZURE_SUBSCRIPTION_ID
"Resource Provider Not Registered"
Register required resource providers:
az provider register --namespace Microsoft.Compute
az provider register --namespace Microsoft.Storage
az provider register --namespace Microsoft.Sql
az provider register --namespace Microsoft.CostManagement
Missing Metrics Data
Ensure Azure Monitor is enabled for your resources:
# Check if metrics are available
az monitor metrics list --resource "/subscriptions/.../virtualMachines/myVM"
Slow Scans
For large subscriptions:
# Reduce scope to specific service categories
cca scan --provider azure --services compute,storage
# Or scan a single region
cca scan --provider azure --regions eastus
Sign-in blocked by security defaults (AADSTS530035)
If az login or cca setup --provider azure --deploy fails with
AADSTS530035: Access has been blocked by security defaults, your tenant is
blocking the Azure CLI (often on an unmanaged or unregistered device). Fixes, in
order of preference:
- complete MFA registration at aka.ms/mfasetup, then retry; or
- sign in from a registered/compliant device; or
- have a tenant admin adjust the policy at Entra admin center > Identity > Overview > Properties > Manage security defaults. On paid tiers prefer a Conditional Access exclusion over disabling security defaults, and re-enable protection afterward.
Cannot create the service principal
"You don't have permission to access this resource" or an app-registration error means your account cannot register apps. Ask an admin to grant the Application Developer role (or set Users can register applications = Yes), or use the hand-off path in Provisioning access.
Cost Data Requirements
For accurate cost-based recommendations, enable Cost Management:
- Go to Cost Management + Billing in Azure Portal
- Enable Cost Management
- Wait 24-48 hours for data to populate
Next Steps
- AWS Provider - Scan AWS resources
- CLI Commands - Full CLI reference
- CI/CD Integration - Automate scans