Microsoft Azureintermediate

How to Grant IAM Roles for Azure Cost Management Data Export

Configure correct permissions for users and system-managed identities

10 min readUpdated January 2025

How to Grant IAM Roles for Azure Cost Management Data Export

Properly configuring Identity and Access Management (IAM) roles is critical for enabling Azure Cost Management data exports. Without the correct permissions, your exports will fail, and billing data won't reach your storage accounts or analytics platforms. This guide walks you through configuring RBAC (Role-Based Access Control) permissions for both human users and system-managed identities.

Overview

Azure Cost Management requires specific IAM roles to read billing data and write it to storage destinations. The most common roles needed are:

  • Cost Management Reader: Grants read-only access to cost and billing data at subscription or billing scope
  • Cost Management Contributor: Allows creation and management of cost exports
  • Storage Blob Data Contributor: Enables writing export files to Azure Storage accounts

This guide covers three primary scenarios:

  1. Granting permissions to human users managing cost exports
  2. Assigning roles to system-managed identities for automated exports
  3. Configuring storage account permissions for export destinations

Prerequisites

Before you begin, ensure you have:

  • Azure subscription with Owner or User Access Administrator role
  • Azure CLI installed (version 2.30.0 or later) OR access to Azure Portal
  • Azure PowerShell module (optional, for PowerShell method)
  • Billing Account access if configuring exports at billing scope (EA, MCA, or MPA)
  • Basic understanding of Azure RBAC concepts

Understanding Required Roles

Cost Management Roles

Cost Management Reader

  • Scope: Subscription, Resource Group, Management Group, or Billing Account
  • Purpose: Read cost data, view existing exports
  • Use case: Analytics teams, finance personnel viewing costs

Cost Management Contributor

  • Scope: Subscription, Resource Group, Management Group, or Billing Account
  • Purpose: Create, modify, and delete cost exports
  • Use case: Platform engineers configuring automated exports

Cost Management Data Reader (Billing scope only)

  • Scope: Billing Account, Billing Profile
  • Purpose: Read cost data across all subscriptions in EA or MCA
  • Use case: Enterprise-wide cost reporting

Storage Roles

Storage Blob Data Contributor

  • Scope: Storage Account or Container
  • Purpose: Write cost export files to blob storage
  • Required for: System-managed identity running the export

Method 1: Azure Portal (Interactive)

Step 1: Assign Cost Management Roles to Users

  1. Navigate to Azure PortalSubscriptions
  2. Select the subscription you want to configure
  3. Click Access control (IAM) in the left navigation
  4. Click + AddAdd role assignment
  5. In the Role tab:
    • Search for "Cost Management Contributor"
    • Select the role
    • Click Next
  6. In the Members tab:
    • Select User, group, or service principal
    • Click + Select members
    • Search for the user or group by name
    • Click Select
    • Click Next
  7. In the Review + assign tab:
    • Review the configuration
    • Click Review + assign

Repeat this process for "Cost Management Reader" if you need read-only access.

Step 2: Configure Storage Account Permissions

  1. Navigate to your Storage Account where exports will be saved
  2. Click Access control (IAM)
  3. Click + AddAdd role assignment
  4. Search for and select Storage Blob Data Contributor
  5. In the Members tab:
    • For automated exports: Select Managed identity
    • Search for your export's system-managed identity (typically named after your export)
    • For user access: Select User, group, or service principal and search for the user
  6. Click Review + assign

Step 3: Verify Role Assignments

  1. Go back to Access control (IAM)
  2. Click the Role assignments tab
  3. Filter by role name to verify assignments
  4. Look for your user or managed identity in the list

Method 2: Azure CLI (Command Line)

Step 1: Assign Cost Management Contributor Role

# Set variables
SUBSCRIPTION_ID="your-subscription-id"
USER_EMAIL="[email protected]"

# Get the user's object ID
USER_OBJECT_ID=$(az ad user show --id $USER_EMAIL --query id -o tsv)

# Assign Cost Management Contributor at subscription scope
az role assignment create \
  --role "Cost Management Contributor" \
  --assignee-object-id $USER_OBJECT_ID \
  --assignee-principal-type User \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

# Verify assignment
az role assignment list \
  --assignee $USER_OBJECT_ID \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --query "[?roleDefinitionName=='Cost Management Contributor']" \
  --output table

Step 2: Assign Storage Permissions to Managed Identity

# Set variables
STORAGE_ACCOUNT_NAME="yourstorageaccount"
RESOURCE_GROUP="your-resource-group"
MANAGED_IDENTITY_NAME="your-export-identity"

# Get storage account resource ID
STORAGE_ID=$(az storage account show \
  --name $STORAGE_ACCOUNT_NAME \
  --resource-group $RESOURCE_GROUP \
  --query id -o tsv)

# Get managed identity principal ID
MI_PRINCIPAL_ID=$(az identity show \
  --name $MANAGED_IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --query principalId -o tsv)

# Assign Storage Blob Data Contributor role
az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id $MI_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --scope $STORAGE_ID

# Verify assignment
az role assignment list \
  --assignee $MI_PRINCIPAL_ID \
  --scope $STORAGE_ID \
  --output table

Step 3: Assign Billing Scope Permissions (Enterprise Agreement)

# For EA billing accounts
BILLING_ACCOUNT_ID="your-billing-account-id"

# Assign Cost Management Reader at billing scope
az role assignment create \
  --role "Cost Management Reader" \
  --assignee-object-id $USER_OBJECT_ID \
  --assignee-principal-type User \
  --scope "/providers/Microsoft.Billing/billingAccounts/$BILLING_ACCOUNT_ID"

Method 3: Azure PowerShell

Step 1: Install and Connect

# Install Azure PowerShell module (if not already installed)
Install-Module -Name Az -Repository PSGallery -Force -AllowClobber

# Connect to Azure
Connect-AzAccount

# Set subscription context
Set-AzContext -SubscriptionId "your-subscription-id"

Step 2: Assign Cost Management Roles

# Define variables
$subscriptionId = "your-subscription-id"
$userEmail = "[email protected]"
$scope = "/subscriptions/$subscriptionId"

# Get user object
$user = Get-AzADUser -UserPrincipalName $userEmail

# Assign Cost Management Contributor role
New-AzRoleAssignment `
  -ObjectId $user.Id `
  -RoleDefinitionName "Cost Management Contributor" `
  -Scope $scope

# Assign Cost Management Reader role
New-AzRoleAssignment `
  -ObjectId $user.Id `
  -RoleDefinitionName "Cost Management Reader" `
  -Scope $scope

# Verify assignments
Get-AzRoleAssignment `
  -ObjectId $user.Id `
  -Scope $scope | Format-Table DisplayName, RoleDefinitionName, Scope

Step 3: Configure Storage Access for Managed Identity

# Define variables
$resourceGroupName = "your-resource-group"
$storageAccountName = "yourstorageaccount"
$managedIdentityName = "your-export-identity"

# Get storage account
$storageAccount = Get-AzStorageAccount `
  -ResourceGroupName $resourceGroupName `
  -Name $storageAccountName

# Get managed identity
$managedIdentity = Get-AzUserAssignedIdentity `
  -ResourceGroupName $resourceGroupName `
  -Name $managedIdentityName

# Assign Storage Blob Data Contributor
New-AzRoleAssignment `
  -ObjectId $managedIdentity.PrincipalId `
  -RoleDefinitionName "Storage Blob Data Contributor" `
  -Scope $storageAccount.Id

# Verify assignment
Get-AzRoleAssignment `
  -ObjectId $managedIdentity.PrincipalId `
  -Scope $storageAccount.Id | Format-Table

Method 4: Azure Resource Manager (ARM) Template

For infrastructure-as-code deployments, use ARM templates to assign roles:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "managedIdentityPrincipalId": {
      "type": "string"
    },
    "storageAccountName": {
      "type": "string"
    }
  },
  "variables": {
    "storageBlobDataContributorRole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
      "apiVersion": "2022-04-01",
      "name": "[concat(parameters('storageAccountName'), '/Microsoft.Authorization/', guid(uniqueString(parameters('storageAccountName'))))]",
      "properties": {
        "roleDefinitionId": "[variables('storageBlobDataContributorRole')]",
        "principalId": "[parameters('managedIdentityPrincipalId')]",
        "principalType": "ServicePrincipal"
      }
    }
  ]
}

Scope-Specific Configurations

Subscription Scope

Best for: Individual subscription cost tracking

# Subscription scope format
SCOPE="/subscriptions/{subscription-id}"

az role assignment create \
  --role "Cost Management Contributor" \
  --assignee-object-id $USER_OBJECT_ID \
  --scope $SCOPE

Resource Group Scope

Best for: Project-specific cost tracking

# Resource group scope format
SCOPE="/subscriptions/{subscription-id}/resourceGroups/{resource-group-name}"

az role assignment create \
  --role "Cost Management Reader" \
  --assignee-object-id $USER_OBJECT_ID \
  --scope $SCOPE

Management Group Scope

Best for: Multi-subscription governance

# Management group scope format
SCOPE="/providers/Microsoft.Management/managementGroups/{management-group-id}"

az role assignment create \
  --role "Cost Management Reader" \
  --assignee-object-id $USER_OBJECT_ID \
  --scope $SCOPE

Billing Account Scope (EA)

Best for: Enterprise-wide cost visibility

# Billing account scope format
SCOPE="/providers/Microsoft.Billing/billingAccounts/{billing-account-id}"

az role assignment create \
  --role "Cost Management Data Reader" \
  --assignee-object-id $USER_OBJECT_ID \
  --scope $SCOPE

Best Practices

1. Principle of Least Privilege

  • Grant Reader roles for users who only need to view costs
  • Reserve Contributor roles for platform administrators
  • Use resource group scope when possible instead of subscription scope

2. Use Azure AD Groups

# Create a cost management group
GROUP_ID=$(az ad group create \
  --display-name "Cost-Management-Analysts" \
  --mail-nickname "cost-analysts" \
  --query id -o tsv)

# Assign role to group instead of individuals
az role assignment create \
  --role "Cost Management Reader" \
  --assignee-object-id $GROUP_ID \
  --assignee-principal-type Group \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

3. Document Role Assignments

Create a documentation table tracking role assignments:

User/IdentityRoleScopePurposeAssigned Date
[email protected]Cost Management ReaderSubscriptionMonthly reporting2025-01-15
cost-export-miStorage Blob Data ContributorStorage AccountAutomated exports2025-01-15

4. Regularly Audit Permissions

# List all cost management role assignments
az role assignment list \
  --all \
  --query "[?contains(roleDefinitionName, 'Cost Management')]" \
  --output table

# Export to CSV for review
az role assignment list \
  --all \
  --query "[?contains(roleDefinitionName, 'Cost Management')].[principalName,roleDefinitionName,scope]" \
  --output tsv > cost-permissions-audit.csv

5. Enable Managed Identities

  • Prefer system-managed identities for cost exports (automatically managed lifecycle)
  • Use user-assigned identities when sharing across multiple exports

6. Separation of Duties

  • Finance teams: Cost Management Reader only
  • Platform teams: Cost Management Contributor + Storage access
  • Automated exports: Managed identity with minimal required permissions

Troubleshooting

Issue: "Authorization failed" when creating export

Symptoms: Export creation fails with permission error

Resolution:

# Verify you have Contributor role
az role assignment list \
  --assignee $(az ad signed-in-user show --query id -o tsv) \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --query "[?roleDefinitionName=='Cost Management Contributor']"

# If missing, request from subscription owner

Issue: Export runs but no data appears in storage

Symptoms: Export shows as successful but files not created

Resolution:

# Check managed identity has storage permissions
EXPORT_IDENTITY=$(az costmanagement export show \
  --name "MyExport" \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --query identity.principalId -o tsv)

az role assignment list \
  --assignee $EXPORT_IDENTITY \
  --scope $STORAGE_ID \
  --query "[?roleDefinitionName=='Storage Blob Data Contributor']"

# If missing, assign the role
az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id $EXPORT_IDENTITY \
  --assignee-principal-type ServicePrincipal \
  --scope $STORAGE_ID

Issue: Cannot see billing account costs

Symptoms: Cost data shows $0 or missing subscriptions

Resolution:

# Verify billing scope permissions
BILLING_SCOPE="/providers/Microsoft.Billing/billingAccounts/{billing-account-id}"

az role assignment list \
  --assignee $(az ad signed-in-user show --query id -o tsv) \
  --scope $BILLING_SCOPE

# Request Billing Account Reader or Cost Management Data Reader from billing admin

Issue: Role assignment fails with "Principal not found"

Symptoms: Role assignment command returns principal does not exist error

Resolution:

# For users: ensure UPN is correct
az ad user show --id [email protected]

# For managed identities: ensure it exists
az identity show --name identity-name --resource-group rg-name

# For service principals: use application ID
az ad sp show --id {app-id}

Issue: Permissions work in Portal but not CLI

Symptoms: Can create exports in Portal but CLI commands fail

Resolution:

# Refresh CLI token
az account get-access-token --query accessToken -o tsv

# Clear and re-login
az logout
az login

# Verify correct subscription
az account show
az account set --subscription "subscription-name"

Verification Script

Use this PowerShell script to verify all required permissions are in place:

# Cost Management Permissions Verification Script
param(
    [Parameter(Mandatory=$true)]
    [string]$SubscriptionId,

    [Parameter(Mandatory=$true)]
    [string]$StorageAccountName,

    [Parameter(Mandatory=$true)]
    [string]$ResourceGroupName,

    [Parameter(Mandatory=$false)]
    [string]$ManagedIdentityName
)

Write-Host "Verifying Cost Management Permissions..." -ForegroundColor Cyan

# Set context
Set-AzContext -SubscriptionId $SubscriptionId | Out-Null

# Check current user permissions
$currentUser = Get-AzContext
Write-Host "`nCurrent User: $($currentUser.Account.Id)" -ForegroundColor Yellow

$userRoles = Get-AzRoleAssignment `
    -SignInName $currentUser.Account.Id `
    -Scope "/subscriptions/$SubscriptionId" `
    | Where-Object { $_.RoleDefinitionName -like "*Cost Management*" }

if ($userRoles) {
    Write-Host "✓ User has Cost Management roles:" -ForegroundColor Green
    $userRoles | ForEach-Object { Write-Host "  - $($_.RoleDefinitionName)" }
} else {
    Write-Host "✗ User missing Cost Management roles" -ForegroundColor Red
}

# Check storage account permissions
$storageAccount = Get-AzStorageAccount `
    -ResourceGroupName $ResourceGroupName `
    -Name $StorageAccountName

if ($ManagedIdentityName) {
    $identity = Get-AzUserAssignedIdentity `
        -ResourceGroupName $ResourceGroupName `
        -Name $ManagedIdentityName

    $storageRoles = Get-AzRoleAssignment `
        -ObjectId $identity.PrincipalId `
        -Scope $storageAccount.Id `
        | Where-Object { $_.RoleDefinitionName -like "*Storage Blob Data*" }

    if ($storageRoles) {
        Write-Host "✓ Managed Identity has storage permissions:" -ForegroundColor Green
        $storageRoles | ForEach-Object { Write-Host "  - $($_.RoleDefinitionName)" }
    } else {
        Write-Host "✗ Managed Identity missing storage permissions" -ForegroundColor Red
    }
}

Write-Host "`nVerification complete!" -ForegroundColor Cyan

Run the verification script:

.\Verify-CostPermissions.ps1 `
    -SubscriptionId "your-sub-id" `
    -StorageAccountName "yourstorage" `
    -ResourceGroupName "your-rg" `
    -ManagedIdentityName "cost-export-identity"

Next Steps

Once permissions are configured:

  1. Create your first export: Follow the "How to Set Up Azure Cost Management Data Export" guide
  2. Monitor export health: See "How to Monitor Cost Export Status and Data Freshness in Azure"
  3. Secure your data: Review "How to Secure Cost Management Data in Azure Storage and Synapse"
  4. Set up alerts: Configure budget alerts with "How to Set Up Cost Alerts and Budgets in Azure"

Related Resources

Need Professional Help?

Our team of experts can help you implement and configure these solutions for your organization.