Skip to main content

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.

ServiceResource TypesOptimization Rules
Virtual MachinesVMsRightsizing, Reserved Instance coverage, Hybrid Benefit
Managed DisksDisksDiscovery only (rules planned)
Storage AccountsBlob, File, TableDiscovery only (rules planned)
SQL DatabaseDatabasesDiscovery only (rules planned)
Load BalancersStandard, BasicDiscovery only
Public IPsStatic, DynamicDiscovery only
Network InterfacesNICsDiscovery only

Authentication

CCA supports multiple Azure authentication methods:

# Login interactively
az login

# Set subscription
az account set --subscription "My Subscription"

# Run scan
cca scan --provider azure

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
Planned

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:

  1. Go to Cost Management + Billing in Azure Portal
  2. Enable Cost Management
  3. Wait 24-48 hours for data to populate

Next Steps