---
title: Grant CloudMonitor access to Azure
canonical: "https://cloudmonitor.ai/docs/cloudmonitor-on-fabric/granting-cloudmonitor-access-to-your-azure-environment/"
description: "Authorize the CloudMonitor service principal and grant read-only access to subscriptions, billing, and cost-export storage."
---

import ArchitectureDiagram from '~/components/docs/ArchitectureDiagram.astro';
import DownloadPdfButton from '~/components/DownloadPdfButton.astro';
import { CardGrid, LinkCard } from '@astrojs/starlight/components';

This guide explains exactly what
you need to do so CloudMonitor can read your cost and usage data and start
producing FinOps insights for your organization.

Every permission this guide asks for follows the principle of **least
privilege** — the minimal access CloudMonitor needs to read your cost and usage
data, and nothing more. It's **read-only** wherever Azure allows; the only
write or management access anywhere in the guide is the minimal role needed to
create and run the scheduled cost export (see [Step 4](#step-4--set-up-the-cost-data-export-storage)).

<DownloadPdfButton />

Two ways to grant access. Most teams click through the Azure portal; if you
prefer the command line, an optional script makes the same grants for you. Both
reach the same read-only result.

<CardGrid>
  <LinkCard
    title="Follow the step-by-step guide"
    description="Recommended. Click through the Azure portal at your own pace, with a short explanation at every grant. This is the fully supported path and is complete on its own — start at Step 1."
    href="#step-1--authorize-the-cloudmonitor-application"
  />
  <LinkCard
    title="Run the optional PowerShell script"
    description="Optional shortcut for command-line teams. The wizard signs in to your own tenant and asks before each change — read-only wherever Azure allows, and safe to re-run. You don't need it to finish the guide."
    href="/downloads/Grant-CloudMonitorAccess.ps1"
  />
</CardGrid>

:::tip[Running the script]
After you [download `Grant-CloudMonitorAccess.ps1`](/downloads/Grant-CloudMonitorAccess.ps1), review it, then run it from a PowerShell prompt:

```powershell
# Preview every change without touching Azure
.\Grant-CloudMonitorAccess.ps1 -DryRun

# Run it for real
.\Grant-CloudMonitorAccess.ps1
```

The portal steps below stay the primary, fully supported path — the script is
just a convenience for teams who prefer the command line.
:::

CloudMonitor connects through a **multi-tenant service principal** that we
provide. You authorize our application, grant it **read-only** access to the
subscriptions and billing scope you choose, and create one dedicated storage
account that receives your scheduled cost exports. Our backend then reads your
cost and usage data from that export and through the Azure APIs.

<ArchitectureDiagram />

:::note[CloudMonitor is read-only and cannot make any changes to your resources]
Every access role below is a *reader* role: CloudMonitor can see service
metadata and costs, but **cannot** change your resources and **cannot** read
the data inside your services — for example, key vault secrets, database
contents, or application blobs.
:::

## What we send you

We send you **one thing: the admin consent URL** (used in Step 1). You don't
need any IDs from us up front.

:::note
This step has already been done — it was completed when you signed up via our [get-started page](https://cloudmonitor.ai/get-started/). You can skip ahead to [Step 2](#step-2--prepare-your-subscriptions).
:::

When you open that URL and approve it, Azure automatically creates the
CloudMonitor application in your tenant. It always has the same fixed
identifiers, so you can recognize and look it up afterwards:

| Identifier | Value |
| --- | --- |
| **Display name** | `cloudmonitor` |
| **Application (client) ID** | `ef7bf83e-23c6-4d84-962b-a3b0f14695a5` |

Use the display name **`cloudmonitor`** (or the client ID above) to find
and select the service principal whenever you assign roles in the steps below —
or any time you want to look it up in Microsoft Entra.

After you finish, you simply let us know — see
[Let us know when you're done](#let-us-know-when-youre-done).

## Step 1 — Authorize the CloudMonitor application

:::note[Who needs to do this]
A **Cloud Application Administrator** (or **Global Administrator**) in your tenant.
:::

This is a one-time action. It provisions the CloudMonitor service principal in
your tenant so you can assign it the read-only Azure roles in Steps 2 and 3.
CloudMonitor requests **no directory or Microsoft Graph permissions** — all of
its access comes from the Azure role assignments you make below.

1. An administrator opens the **admin consent URL** we provided
   (it looks like
   `https://login.microsoftonline.com/<your-tenant-id>/adminconsent?client_id=ef7bf83e-23c6-4d84-962b-a3b0f14695a5`).
2. Sign in and click **Accept**. Because CloudMonitor requests no directory
   permissions, this simply creates the application in your tenant — it does
   not grant any access on its own.
3. Once complete, a matching entry appears in your tenant under
   **Microsoft Entra ID → Enterprise applications**. You can confirm it by
   searching for the display name **`cloudmonitor`** (or the client ID
   above).

## Step 2 — Prepare your subscriptions

Two subscription-level tasks: grant CloudMonitor **read access** (2a), then make
sure the **cost-export resource provider** is registered (2b).

### 2a — Grant subscription read access

:::note[Who needs to do this]
A **User Access Administrator** (or **Owner**) on the subscription or management group scope.
:::

Do this for **each Azure subscription** you want CloudMonitor to monitor. If
you use **management groups**, assign the role once at the management-group
scope and every current and future subscription underneath is covered
automatically — this is the recommended approach.

1. In the [Azure portal](https://portal.azure.com), open the **subscription**
   (or **management group**) you want to monitor.
2. Select **Access control (IAM)**.
3. Click **+ Add → Add role assignment**.
   - If **+ Add** is greyed out, your account does not have the **Owner**
     role on this scope. Ask whoever does to complete this step.
4. On the **Role** tab, select **Reader**, then click **Next**.
5. On the **Members** tab, choose **User, group, or service principal** and
   click **Select members**.
6. Search for **`cloudmonitor`** (or paste the client ID above), select
   it, and click **Select**.
7. Click **Review + assign**.
8. Repeat for any additional subscriptions, or use a management group to cover
   them all at once.

:::note
**Reader** lets CloudMonitor read service-plane metadata and costs only. It
cannot modify resources and cannot read data inside services.
:::

### 2b — Register the export resource provider

:::note[Who needs to do this]
A **Contributor** (or **Owner**) on the subscription that will hold your
cost-export storage account.
:::

The scheduled Cost Management export that lands in your storage account
([Step 4](#step-4--set-up-the-cost-data-export-storage)) needs the
**`Microsoft.CostManagementExports`** resource provider registered on the
subscription that will hold that account. **It's often already registered** — so
just check, and register it only if it isn't. Since you're already working at the
subscription level here, it's a quick one to knock out now.

1. Open the **subscription** that will hold your cost-export storage account.
2. Select **Resource providers**.
3. Search for **`Microsoft.CostManagementExports`** and check the **Status**. If
   it shows **Registered**, there's nothing to do. If it shows **NotRegistered**,
   select it and click **Register**.

For more on registering providers, see Microsoft's guide to
[Azure resource providers](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types).

## Step 3 — Grant billing access

Cost data is most complete when CloudMonitor reads it at the **billing
account** scope. The exact steps depend on your **billing agreement type**.

Not sure which you have? See Microsoft's guide:
[Check the type of your billing account](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/manage-billing-access#check-the-type-of-your-billing-account).

Choose the section that matches your agreement:

- [3a. Microsoft Customer Agreement (MCA)](#3a--microsoft-customer-agreement-mca)
- [3b. Enterprise Agreement (EA, legacy)](#3b--enterprise-agreement-ea-legacy)
- [3c. No billing-account access (or running through a CSP)](#3c--no-billing-account-access-or-running-through-a-csp)

:::note
Only **MCA** and **EA** billing accounts are supported at the billing scope.
Other account types (for example, pay-as-you-go / MOSP or credit accounts)
should use the [subscription-scope fallback](#3c--no-billing-account-access-or-running-through-a-csp).
:::

### 3a — Microsoft Customer Agreement (MCA)

:::note[Who needs to do this]
A **Global Administrator** with billing-account access.
:::

1. In the Azure portal, open **Cost Management + Billing**.
   *(This is at the billing-account level, not the subscription level.)*
2. Select the **billing scope** (billing account or billing profile) you want
   CloudMonitor to read.
3. Select **Access control (IAM)** and click **+ Add**.
4. Choose the **Billing account reader** role. *(This role has no write
   permissions.)*
5. Select the CloudMonitor application and click **Add**.

:::note[Next: skip to Step 4]
That's everything for MCA billing access. **Step 3c doesn't apply to you** — it's
only for accounts without billing-account access. Skip ahead to
[Step 4 — Set up the cost-data export storage](#step-4--set-up-the-cost-data-export-storage).
:::

:::caution[Known Microsoft limitation on MCA]
Microsoft currently restricts some service principals from reading cost data on
certain MCA billing accounts. If our team confirms CloudMonitor isn't receiving
your MCA cost data after this step, we will fall back to the
[subscription-scope method](#3c--no-billing-account-access-or-running-through-a-csp),
which works reliably. We'll guide you if that's needed — no action required
from you up front.
:::

### 3b — Enterprise Agreement (EA, legacy)

:::note[Who needs to do this]
An EA **Department Administrator** or **Account Owner**. If you don't hold one of these roles, ask your Enterprise Administrator to assign one to you.
:::

EA billing roles can't be assigned in the Azure portal, so this uses the Azure
Billing REST API.

1. Open the REST API "Try it" page:
   [Billing Role Assignments — Put](https://learn.microsoft.com/en-us/rest/api/billing/2019-10-01-preview/role-assignments/put?tabs=HTTP#code-try-0).
   - Sign in with an admin account.
   - Select the AD tenant that you authorized in Step 1.
2. Fill in the **parameters**:
   - **`billingAccountName`** — your **Billing account ID**, found on the
     **Cost Management + Billing** overview page.
   - **`billingRoleAssignmentName`** — a new, unique GUID. Generate one at
     [guidgenerator.com](https://guidgenerator.com).
3. Paste this into the **Body**, replacing the placeholders:

   ```json
   {
     "properties": {
       "principalId": "<cloudmonitor-service-principal-object-id>",
       "principalTenantId": "<your-tenant-id>",
       "roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/<your-billing-account-id>/billingRoleDefinitions/24f8edb6-1668-4659-b5e2-40bb5f3a7d7e"
     }
   }
   ```

   - **`principalId`** — the **Object ID** of the CloudMonitor app *in your
     tenant*. Find it under **Microsoft Entra ID → Enterprise applications**,
     search for **`cloudmonitor`**, and copy its **Object ID**.
   - **`principalTenantId`** — your **Directory (tenant) ID**.
   - **`<your-billing-account-id>`** — the same value you used for
     `billingAccountName`.
   - `24f8edb6-1668-4659-b5e2-40bb5f3a7d7e` is the fixed role-definition ID for
     the read-only **EnrollmentReader** role — leave it as-is.
4. Click **Run**. A **200** status means success.
   - **400** — recheck every field.
   - **403** — your account doesn't have permission; sign in as an Account
     Owner or Department Administrator.

:::note[Next: skip to Step 4]
That's everything for EA billing access. **Step 3c doesn't apply to you** — it's
only for accounts without billing-account access. Skip ahead to
[Step 4 — Set up the cost-data export storage](#step-4--set-up-the-cost-data-export-storage).
:::

### 3c — No billing-account access (or running through a CSP)

:::note[Who needs to do this]
A **User Access Administrator** (or **Owner**) on each subscription.
:::

Use this if you don't have access to your billing account (for example, your
CSP or managed service provider holds it), or if the MCA limitation above
applies. CloudMonitor reads cost data at the **subscription** scope instead.

1. In the Azure portal, open a **subscription** that CloudMonitor already has
   **Reader** access to (from Step 2a).
2. Select **Access control (IAM)** → **+ Add → Add role assignment**.
3. On the **Role** tab, select **Cost Management Contributor**.
4. On the **Members** tab, click **Select members**, search for the
   CloudMonitor application, and select it.
5. Click **Review + assign**.
6. Repeat for each subscription you want cost data from.

:::caution[What you give up with subscription-scope billing]
Because some data only exists at the billing-account level, this method
**cannot** show:

- Marketplace and other billing-account purchases,
- Reservation (RI) net savings, utilization, and order details,
- Microsoft 365 license costs,
- a single holistic view across the whole organization.

Reservation (RI) data isn't available at subscription scope, and under a CSP the
reservations are held in your **partner's** tenant — so they can't be read from
yours at all. Full reservation reporting is available only with **MCA** or **EA**
billing-account access ([3a](#3a--microsoft-customer-agreement-mca) or
[3b](#3b--enterprise-agreement-ea-legacy)), so we recommend billing-account
access whenever possible.
:::

## Step 4 — Set up the cost-data export storage

:::note[Who needs to do this]
A **Contributor** + **User Access Administrator** (or **Owner**) on the subscription where you will create the storage account.
:::

CloudMonitor receives your detailed cost data through a scheduled Azure Cost
Management export. You create **one dedicated storage account** for these
exports and grant the CloudMonitor service principal access to it. (The export
resource provider this relies on is registered back in
[Step 2b](#2b--register-the-export-resource-provider).) CloudMonitor authenticates
to this storage account using the service principal you authorized in Step 1 —
no access keys are shared.

**Your data stays in your storage account.** Rather than copying it out,
CloudMonitor reads the exported files in place using a **Microsoft Fabric
OneLake shortcut** — a reference that surfaces your storage account directly
inside our Fabric pipeline, so there's no second copy of your data and no
separate transfer to manage. You can read more about
[OneLake shortcuts](https://learn.microsoft.com/en-us/fabric/onelake/onelake-shortcuts).

:::note[The storage account must be Data Lake Storage Gen2]
Because the Fabric shortcut reads the export over the Data Lake (ADLS Gen2)
endpoint, the storage account must be a **general-purpose v2** account with
**hierarchical namespace** (Azure hierarchical folders) **enabled** — see
Step 4a.
:::

### 4a — Create the storage account

1. In the Azure portal, go to **Storage accounts** and click **Create**.
2. **Select the subscription.** Choose one of your existing subscriptions, or
   create a new one, to host the new CloudMonitor exports landing zone. Treat its
   contents as **production data** and apply all your existing company policies
   (governance, access, retention, and the like). Then, under **Resource group**,
   click **Create new** and make a dedicated resource group for these cost
   exports. So the group is easy to find, audit, and remove later, do at least
   one of the following: give it a name that includes **CloudMonitor** (for
   example,
   `rg-cloudmonitor-exports`), or tag the resource group **`Purpose` =
   `CloudMonitor Exports`** from its own **Tags** page once it exists. (The
   **Tags** tab in this wizard tags the storage account, not the new resource
   group, so set the group's tag from the resource group itself.)
3. **Name** the storage account per your organization's naming conventions.
4. Leave the default **Standard** performance and **Azure Blob Storage or Azure
   Data Lake Storage Gen2** primary service — this creates a **general-purpose
   v2 (StorageV2)** account.
5. **Region** — choose the region closest to your main workloads to avoid
   egress charges.
6. **Redundancy** — **LRS** is sufficient.
7. On the **Advanced** tab, **enable Hierarchical namespace** (Azure Data Lake
   Storage Gen2 — the "hierarchical folders" option). This is **required** so
   CloudMonitor can read the exports through a Fabric OneLake shortcut.
8. Click **Review + create**.

:::note[This storage account is the only infrastructure CloudMonitor needs]
Aside from this account, your whole setup is access grants and configuration — no
other resources are deployed in your tenant. This one storage account, in its
dedicated resource group, is the only thing you create. The export files are
small and Data Lake storage is inexpensive, but they accumulate, so the account's
cost grows slowly over time. To cap that, apply an [Azure Blob Storage lifecycle
management policy](https://learn.microsoft.com/azure/storage/blobs/lifecycle-management-overview)
that automatically deletes exports older than a retention window you choose.
Because CloudMonitor reads the exports in place rather than keeping its own copy,
deleting an export also removes that period from your reports — so keep enough
history for the trends and year-over-year views you rely on, and expire only
older data beyond that.
:::

### 4b — Grant CloudMonitor access to the storage account

CloudMonitor's service principal does two distinct things with this account, so
it needs **two role assignments** here — and nothing else:

- **Storage Account Contributor** — lets CloudMonitor **create and run the
  scheduled Cost Management export** that lands your cost files in this account.
  Pointing an export at a storage account requires management-plane **write on
  that account**, which the **Cost Management Contributor** role from Step 3
  doesn't include. This role is for *setting up* the export, not for reading your
  data — reading is handled by the **Storage Blob Data Reader** role below (see
  the note for a stricter, no-keys variant).
- **Storage Blob Data Reader** — lets CloudMonitor **read the exported files in
  place** through the Fabric OneLake shortcut. Read-only is all that's needed:
  the export's writes are performed by Azure Cost Management itself (via the copy
  permission you set in 4c), not by CloudMonitor.

Assign both roles to **`cloudmonitor`**, scoped to **this one storage
account only**:

1. Open the storage account you created in Step 4a.
2. Select **Access control (IAM)** → **+ Add → Add role assignment**.
3. On the **Role** tab, select **Storage Account Contributor**, then **Next**.
4. On the **Members** tab, click **Select members**, search for
   **`cloudmonitor`**, select it, click **Select**, then **Review +
   assign**.
5. Repeat **+ Add → Add role assignment** for the **Storage Blob Data Reader**
   role, assigning it to **`cloudmonitor`** the same way.

:::note
Both roles apply only to this one storage account, which exists solely to receive
your cost exports — CloudMonitor gets no access to your other resources or
services, and authenticates over Microsoft Entra ID (no access keys are shared).
**Storage Account Contributor** is a management role that *can* list the account
keys; if you'd rather rule that out, replace it with a **custom role** granting
only `Microsoft.Storage/storageAccounts/write` (plus read) without `listKeys`.
:::

### 4c — Allow cost-export write operations

1. On the same storage account, open **Configuration**.
2. Set **Permitted scope for copy operations** to **"From any storage
   account"**.
3. Click **Save**.

This lets Azure Cost Management write the scheduled export data into the
account.

## Let us know when you're done

You don't need to send us any IDs. Once you've completed the steps above, just
**email [support@cloudmonitor.ai](mailto:support@cloudmonitor.ai) to let us know it's done** — we can take care of the rest from our
side.

## What happens next

1. **We run a health check** on your setup to confirm the permissions and the
   cost export are working as expected.
2. **We extract your data** and build your CloudMonitor reports.
3. **We email you the link** to your reports, at the address you gave us.

Run into a problem at any point? [Click here to raise a ticket](#chatbox) and
our support team will help.

## Quick reference — everything CloudMonitor asks for

| Scope | Role / permission | How it's granted | Access level |
| --- | --- | --- | --- |
| Subscription / management group | **Reader** | IAM role assignment (Step 2a) | Read-only |
| Billing account — MCA | **Billing account reader** | IAM role assignment (Step 3a) | Read-only |
| Billing account — EA | **EnrollmentReader** | Billing REST API (Step 3b) | Read-only |
| Subscription — billing fallback (**not for MCA or EA**) | **Cost Management Contributor** | IAM role assignment (Step 3c) | Cost data only |
| Cost-export storage account (one dedicated account) | **Storage Account Contributor** | IAM role assignment (Step 4b) | Create & run the export on this one account; no blob data access |
| Cost-export storage account (same account) | **Storage Blob Data Reader** | IAM role assignment (Step 4b) | Read-only access to the exported blob data |

Questions at any point? Reach out to your CloudMonitor contact — we're happy to
walk through any step with you.
