Skip to main content

Connect Azure

Connecting Azure gives Orbit a read-only service principal (for resource inventory) and a FOCUS cost export in blob storage (for cost). This guide supports both tenant-wide (all subscriptions) and single-subscription onboarding.

You can set up the Azure side in two ways: run the Cloud Shell script, which does every Azure step and saves the values Orbit asks for, or follow the Azure portal steps by hand.

In Settings > Provider Accounts > Connect account, pick Azure and choose your scope. The wizard then collects the values you create below.

Orbit's Connect account wizard: Azure


Before you begin​

Check your billing agreement type​

Orbit uses Azure FOCUS (FinOps Open Cost and Usage Specification) exports. Verify your agreement supports this:

Agreement typeFOCUS export supportNotes
Enterprise Agreement (EA)SupportedBilling account (enrollment), Department, Enrollment account, Subscription and Resource Group scopes
Microsoft Customer Agreement (MCA)SupportedAll scopes including Billing Profile
MCA via Partner (MPA)SupportedCustomer, Subscription, Resource Group
Pay-As-You-Go on a Microsoft Customer AgreementSupportedSame scopes as MCA
Pay-As-You-Go, older agreement (Microsoft Online Services Program)Not supportedMicrosoft offers no FOCUS exports for this agreement
Azure SponsorshipNot supportedUse Azure Sponsorship Portal
Microsoft for StartupsNot supportedCost Management not available
Classic CSPNot supportedMust transition to MCA
Management Group scope limitation

FOCUS exports do not support Management Group scope. For tenant-wide, create one export at the billing scope that covers your subscriptions: the Billing Account or a Billing Profile (MCA), or the Billing Account (EA). Don't create one export per subscription in the same folder: Orbit reads one Folder prefix per connection, and exports that share a folder overwrite each other's files.

The Cloud Shell script creates the export at your MCA billing account, which covers all its billing profiles. If your subscriptions are billed on more than one billing account, connect each subscription separately (Single subscription) for now.

Find your agreement type​

  1. In the Azure portal, go to Cost Management + Billing and open your billing account
  2. Select Properties in the left menu
  3. Look at the Type field (some accounts label it Agreement type), for example Microsoft Customer Agreement

Prerequisites​

Required Azure roles​

RolePurposeSingle subscriptionTenant-wide
Application AdministratorCreate the service principalMicrosoft Entra IDMicrosoft Entra ID
OwnerCreate the storage account and assign roles. For a single subscription, also create the cost exportThe subscriptionThe Tenant Root Group
Owner, contributor or reader (billing role, MCA)Create the tenant-wide cost exportNot neededThe billing account. With the Azure portal steps, a role on the billing profile is also enough

You don't need Application Administrator if your tenant lets every user register apps. Instead of Owner, you can have Contributor plus User Access Administrator at the same scope.

Enable cost visibility (required for some agreements)​

Enterprise Agreement (EA)

The EA administrator must enable view charges for account owners:

  1. Go to Cost Management + Billing, then select your billing account
  2. Navigate to Policies
  3. Enable AO view charges (Account Owner view charges). If you use department scope, also enable DA view charges (Department Admin view charges)

Without this, you'll see error: AccountCostDisabled or DepartmentCostDisabled

Microsoft Customer Agreement (MCA)

A Billing Profile Owner must let subscription users see Azure usage charges:

  1. Go to Cost Management + Billing, then select your billing account
  2. Select Billing profiles, then choose your profile
  3. Navigate to Policies
  4. Under Azure charges, set Azure usage charges to Yes
CSP Customer

Your CSP partner must enable cost visibility:

  1. Partner signs into Azure Portal with their CSP credentials
  2. Goes to Cost Management + Billing > Billing Scopes
  3. Selects your customer tenant
  4. Under Settings > Policies, enables cost visibility

Without this, you cannot access Cost Management in your tenant.

New subscription?​

New Azure subscriptions take up to 48 hours to appear in Cost Management. If you just created the subscription, wait before proceeding.


Set up Azure​

Pick one method. Each one ends with the seven values Orbit asks for.

The setup script, SKYXOPS-Azure-Setup.ps1, runs in Azure Cloud Shell (PowerShell), which already has everything it needs. It asks a few questions and shows you a plan. Nothing changes in Azure until you approve the plan. Then it creates the Azure side and saves the values Orbit asks for in one file.

Before you run it
  • Sign in to the Azure portal with an account that has the roles in Prerequisites.
  • The script works in the Azure public cloud only.
  • If you use an existing storage account, it must allow public network access from all networks, and its Permitted scope for copy operations must stay From any storage account. The script refuses a storage account whose network access is restricted, and it never changes these settings.
Tenant-wide with the script

The script's Tenant-wide mode works only with a Microsoft Customer Agreement (MCA):

  • The subscriptions your account can see must be billed on one billing account. Several billing profiles under it are fine. If they're billed on more than one billing account, Plan stops before anything changes. For now, connect each subscription separately (Subscription mode).
  • Your account needs the Billing account owner, contributor or reader role. A billing profile role isn't enough. See Prerequisites.
  • A Global Administrator usually has to elevate access before anyone can assign roles on the Tenant Root Group.
  • The export covers the whole billing account: every billing profile under it, and every subscription billed on it, including subscriptions from other tenants. Orbit's cost totals include them all. If the billing profiles use different currencies, the export has costs in each currency.
  • Plan lists any subscription it can't cover under Not covered, for example one on an older pay-as-you-go agreement. Orbit still scans its resources, but its costs won't appear.
  • Orbit scans every subscription under the Tenant Root Group, including ones your account can't see. Their costs appear only if they're billed on this billing account.
  • Connect each tenant once. If Orbit already has a connection for any of these subscriptions, remove it first.

For an Enterprise Agreement (EA), use the Azure portal tab.

Step 1: Open Cloud Shell and upload the script​

  1. Download SKYXOPS-Azure-Setup.ps1.
  2. In the Azure portal, open Cloud Shell from the top bar and choose PowerShell.
  3. Select Manage files > Upload and choose SKYXOPS-Azure-Setup.ps1. Cloud Shell saves it in your home folder, which is where the prompt starts. Run every command below from there.

You don't need to mount a storage account for Cloud Shell. Without one, Cloud Shell deletes your files when the session ends, so Step 4 saves the credentials file to your computer.

Step 2: Run Plan​

./SKYXOPS-Azure-Setup.ps1 -Action Plan

Plan shows the tenant you're signed in to, then asks up to four questions. When it lists choices, type the number of your choice.

  1. Choose the connection mode: 1 for Subscription, 2 for Tenant-wide.
  2. Choose the subscription to connect. In Tenant-wide mode, it's the subscription that holds the storage account. Plan skips this question if you can see only one subscription.
  3. For storage, pick a new storage account just for SKYXOPS, or one of your existing storage accounts in that subscription. Plan skips this question if that subscription has no storage accounts (it creates a new one), or if an earlier run of the script created one (it reuses it).
  4. For a new storage account, type a region name such as westeurope, or press Enter for eastus. For an existing storage account, Plan asks which one instead.

Plan remembers your answers and prints a summary, including the Folder prefix you'll enter in Orbit. Plan changes nothing in Azure. Check that the Tenant line shows the tenant you want to connect. If it shows another tenant, switch the Azure portal to the right directory, open Cloud Shell again and run Plan with -StartOver (below).

Running Plan again reuses your answers. To change an answer before Apply, run Plan with -StartOver, and it asks the questions again:

./SKYXOPS-Azure-Setup.ps1 -Action Plan -StartOver

-StartOver works only before Apply has set anything up.

Step 3: Run Apply​

./SKYXOPS-Azure-Setup.ps1 -Action Apply

Apply shows the plan again. To approve it, type APPLY, a space and your tenant ID, exactly as the script shows. Apply then creates everything listed in What the script creates, and prints the Folder prefix and the date the client secret expires.

If Apply stops with an error, fix the cause and run Apply again. It reuses what it already created, and it never replaces an existing client secret.

Step 4: Save the credentials file to your computer​

Do this straight after Apply. Cloud Shell can delete its files when the session ends, and a session ends after 20 minutes without typing.

download $HOME/SKYXOPS-Credentials.json

This sends the file to your browser as a download.

SKYXOPS-Credentials.json holds the seven values for Orbit, including the client secret. Keep it private. Apply writes this file once, when it first finishes, and never again. If you lose it before the values are in Orbit, create a new client secret on the app (see the note below). The app's Overview page in Microsoft Entra ID and Plan's summary show the other values.

Next, enter the values in Orbit, as described in Enter values in Orbit.

The client secret expires after 90 days

Apply prints the expiry date. You can also find it on the app's Certificates & secrets page. Before then, create a new client secret on the same app: Microsoft Entra ID > App registrations > your skyxops-cost-reader-… app > Certificates & secrets > New client secret. In Orbit, open the connection, select Edit connection, paste the new secret's Value (not its Secret ID) and select Save & re-validate. Delete the old secret only after Orbit shows the connection as Verified.

If Cloud Shell deleted your files

If you come back in a new Cloud Shell session and your files are gone:

  • If you saved SKYXOPS-Credentials.json, the Azure side is done. Don't run the script again. Go to Enter values in Orbit.
  • If Apply finished (it printed the date the client secret expires) but you didn't save the file, create a new client secret on the app, as described above. You can run Plan again to see its summary, but don't run Apply again.
  • If Apply didn't finish, upload the script, then run Plan and Apply again. If Apply stops with AppNameCollision, contact SKYXOPS support.

What the script creates​

Subscription modeTenant-wide mode
App registrationskyxops-cost-reader- + the first 8 characters of the subscription IDskyxops-cost-reader- + the first 8 characters of the tenant ID
The app's rolesReader and Cost Management Reader on the subscriptionReader and Cost Management Reader on the Tenant Root Group
Client secretExpires after 90 daysExpires after 90 days
Storage account, if newstskyxops + 12 letters and digits, in resource group rg-skyxops-focus: Standard, LRS, TLS 1.2, HTTPS only, no anonymous access, public network access onSame, in the subscription you chose in Plan
Containerskyxops-focus, private. The app gets Storage Blob Data Reader on this container onlySame
Cost exportskyxops-focus- + the first 8 characters of the subscription ID, at the subscriptionskyxops-focus- + a 12-character code made from your billing account ID, at the billing account
Export settingsDaily, month-to-date, FOCUS 1.0r2, Parquet with Snappy compression, overwrite on, active for 5 yearsSame
Folder prefixexports/ + the export's nametenant-exports/ + the export's name
Export's identityStorage Blob Data Contributor on the container onlySame

Apply also registers the Microsoft.Storage and Microsoft.CostManagementExports resource providers in the storage subscription if they aren't registered yet. A new storage account adds a small Azure charge.

If the script stops​

When a step stops, the script prints SKYXOPS setup stopped: and a reason, which usually starts with a code. The most common ones:

CodeWhat it meansWhat to do
MissingOperatorPermissionYour account lacks a permission at the scope the message namesGet the role from Prerequisites for that scope (or activate it, if your organization uses Privileged Identity Management), then run the same step again
MissingBillingExportPermission, or AuthorizationFailed during REST GET while Plan asks its questionsTenant-wide: your account has no role on the billing accountGet the Billing account owner, contributor or reader role. A billing profile role isn't enough
MultipleBillingAccountsTenant-wide: your subscriptions are billed on more than one billing accountConnect each subscription in Subscription mode for now
UnsupportedBillingAgreementTenant-wide: none of the subscriptions you can see is billed on a Microsoft Customer Agreement (for example EA, older pay-as-you-go or Visual Studio subscriptions)Use Subscription mode, or the Azure portal tab for an EA
BillingAccountChangedTenant-wide: your subscriptions moved to another billing account after PlanBefore Apply: run Plan with -StartOver. After Apply: contact SKYXOPS support
WrongTenantCloud Shell is signed in to a different tenant from the one in your saved answersSwitch the Azure portal to the tenant you planned for, open Cloud Shell again and run the same step
SubscriptionUnavailableA subscription in your saved answers is no longer enabled, or your account can't see itCheck the subscription in the Azure portal. If it was cancelled, contact SKYXOPS support
UnsupportedNetworkingThe existing storage account limits network accessRun Plan with -StartOver and choose a new storage account
StorageNameUnavailableThe storage account name is taken in AzureRun Plan with -StartOver and choose an existing storage account
AppNameCollisionAn app with the script's name already exists, usually from an earlier ApplyIf that Apply finished, don't run the script again: see the tip in Step 4. Otherwise, contact SKYXOPS support
StartOverAfterApplyYou ran Plan with -StartOver after Apply had set things upRun Apply again to finish, or contact SKYXOPS support
StateConfigMismatchYour saved answers no longer match what Apply already set upContact SKYXOPS support
IncompatibleExportAn export with the script's name already exists, with different settingsContact SKYXOPS support
PartialSetupThe cost export couldn't be set up. The message says whyFix the cause and run Apply again
Any other code, followed by duringAzure refused one of the script's commands. The first word is Azure's error code, for example AuthorizationFailedCheck the roles in Prerequisites, then run the same step again. Don't create a second app or storage account

Enter values in Orbit​

In Orbit, go to Settings > Provider Accounts > Connect account and pick Azure. The wizard has five steps:

  1. On the Subscription step, choose Single subscription and enter the Subscription ID, or choose Tenant-wide discovery. Orbit selects Tenant-wide discovery by default. If you used the script, choose the mode you picked in Plan: Subscription is Single subscription, Tenant-wide is Tenant-wide discovery.

  2. On the Run setup script step, tick I have run the setup script successfully. Tick it too if you used the Azure portal steps.

    The Run setup script step in the Orbit wizard

  3. Enter the Tenant ID, App (Client) ID and Client secret on the Credentials step.

    The Credentials step in the Orbit wizard

  4. Enter the Storage account name, Container name and Folder prefix on the FOCUS storage step.

    The FOCUS storage step in the Orbit wizard

  5. On the Review step, select Connect. Orbit saves the connection and validates it. New roles can take up to 10 minutes to start working, and roles on the Tenant Root Group can take longer. If validation fails straight after setup, wait and try again.

If you used the script, SKYXOPS-Credentials.json holds all seven values under the field names below. In Tenant-wide mode, its Subscription ID says Tenant-wide: choose Tenant-wide discovery instead.

If you used the Azure portal, the table gives the step in the Azure portal tab where you get each value.

FieldExampleSource (Azure portal tab)
Subscription IDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxOnly for Single subscription
Tenant IDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxStep 4: Directory (tenant) ID
App (Client) IDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxStep 4: Application (client) ID
Client secretxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxStep 4: the secret's Value (not its Secret ID)
Storage account namestskyxops####Step 2
Container nameskyxops-cost-exportsStep 3
Folder prefixexports/skyxops-export/skyxops-export-focus-costStep 7: the Directory, then /, then the export's name
Container name and Folder prefix are required

Orbit marks them as optional, but if either is empty, or the Folder prefix stops at the Directory, Orbit loads no costs and shows no error.

To check your Folder prefix, go to your storage account and open Storage browser > Blob containers > your container. Open folders until you see a dated folder such as 20261001-20261031. The Folder prefix is the path of the folder that contains the dated folders.


What happens next​

  1. Orbit validates the connection: it checks the credentials, finds your subscriptions and checks that it can open the container
  2. Orbit loads costs once a day, for the previous day (UTC). Your first costs appear the day after the export's first successful run. Days before that don't appear automatically
  3. Your cost dashboards fill in as each day loads

Quick reference: error summary​

For errors from the setup script, see "If the script stops" in the Cloud Shell script tab.

ErrorCauseSolution
"Not supported"Unsupported subscription typeCheck billing agreement type
"RP registration in progress"Resource provider registeringWait 5 min, retry
AccountCostDisabledEA view charges not enabledEA admin must enable
AuthorizationFailedMissing permissionsNeed Owner/UAA role
StorageAccountAlreadyTakenName not uniqueChoose different name
RequestDisallowedByPolicyAzure Policy blockingAdd required tags
No data after 48 hoursExport not runningCheck export run history
Export shows Succeeded but Orbit shows no costsFolder prefix is empty or stops at the DirectoryFix it with Edit connection in Orbit (see Enter values in Orbit)