Export Azure RateCard data to CSV with C# and Billing API

The Azure Billing API allows to programmatically read Azure costs. On the one hand, there are is the usage of your resources (how much [unit] you already used for [resource]), on the other hand there are the basic costs for resources – so e.g. the costs for a storage account or a specific virtual machine in a specific region. Each of these two use cases has its own API: the RateCard API which returns the potential costs of the resources (“basic costs”) and the Resource Usage API which returns the usage of your resource of a subscription.

In this blog post, I’ll focus on the RateCard API. There is a sample available on GitHub, but when I used it, I ran into some issues. So I decided to developed a simple C# console application and blog about my experiences. The application reads data from the RateCard API and creates a CSV file out of it. The CSV file can be opened in Excel and should already help to do some calculations.

The application/this post is mostly inspired by: https://github.com/Azure-Samples/billing-dotnet-ratecard-api.

Update February 7, 2017: I built a .net library and published it as NuGet package which you can use to get data from the usage api and the ratecard api. The library also combines the usage and ratecard data and calculates the costs. The code is published on GitHub and I blogged about the usage and the configuration of it:

This blog post is still valid, it shows the how to configure and build an application that uses the Azure Billing RateCard REST API.

RateCard C# Application

Please download or clone the solution from GitHub: https://github.com/codehollow/AzureBillingRateCardSample.

Step 1: basic app.config configuration

Open the solution and the app.config and configure the following values:

<add key="Tenant"         value="TENANT.onmicrosoft.com" />
<add key="SubscriptionId" value="SUBSCRIPTIONID" />
 
<!-- RateCard API Parameters -->
<add key="OfferDurableId" value="MS-AZR-0003p" />  <!-- see: https://azure.microsoft.com/en-us/support/legal/offer-details/ -->
<add key="Currency"       value="EUR" />  <!-- EUR, USD, GBP, ... -->
<add key="Locale"         value="en-US" />
<add key="RegionInfo"     value="AT" />
 
<add key="CsvFilePath"    value="c:\data\ratecarddata.csv"/>

The other values will be configured in the next step. So leave the file open so that you can copy and paste the values from the AAD configuration.

Configuration

Before we can run the sample application, we have to add the application to Azure AD and give it the right permissions.

Step 2: add new application to active directory

Open the new portal https://portal.azure.com and navigate to the Active Directory. Open “App registrations” and click the Add Button:

  • Name: billingapi – can be whatever you want
  • Application Type: Native – we use the API from a console application, so native is the right one. If you develop a web application that should access the api, “Web App/API” is the right one for you
  • Redirect URI: http://localhost/billingapi – can be whatever we want, because the console application will not redirect to an url

Copy the Redirect URI and paste it to the app.config to “RedirectUrl”.

Step 3: add permissions to the service management api

When the app is created, open the app (in App registrations), go to Settings and “Required permissions”. Press the add button and add: Windows Azure Service Management API.

Select “Access Azure Service Management as organization users (preview)” and save it:

Step 4: copy the client Id

The client Id is called “Application ID” in the Azure portal. You can find it when you select the app in the “App registrations”. Copy it and paste it to the app.config to “ClientId”.

Step 5: give the user/application access to the subscription

There are two ways how to authenticate. You can sign in with your user or you can use a client id and a client secret to authenticate (application). The first is good if you want to work with a specific user, the second is good for clients that run in the background (azure function, jobs, …)

Depending on what you want to use, you have to give the user or the application “Reader”, “Contributor” or “Owner” access to the subscription.

Navigate to your subscription, select your application and go to “Access control (IAM)”.

If you want to use user and your user does not already have rights, just add the user and give him at least “Reader” access:

If you use application, search for the application and give it at least “Reader” access:

Step 5.1: create client secret (only for authentication via application)

If you use application (see previous step), you need to create a client secret – a key. You can skip this step if you use user authentication. The key can be created by navigating to the active directory – “App registrations” and selecting Keys. Add a new key, give it a name and select a duration:

Press save and copy the key! This is the client secret that needs to be pasted into the app.config – “ClientSecret”.

Run the application

If all steps mentioned in Configuration are done and the app.config is configured, build and run the application. If you use user authentication, you must allow the application (only the first time) to sign in and to access the service management api:

If the application finished successfully, you should find a csv file at the path specified in the app.config (by default: c:\data\ratecarddata.csv)

Troubleshooting

I ran into some issues, so here is what I did:

401 – Unauthorized

There are many reasons why this could happen. Look at the output of the webrequest and check the error_description field. I once got the following message: “The access token is from wrong audience or resource.“.

This issue can be solved by fixing the resource url. The correct value is:
https://management.azure.com/

And…believe or not…the slash / at the end does matter! So if you are using: https://management.azure.com (without / at the end), then you will receive this error!

403 Forbidden

That’s a good message, because it means that you are already logged in! I got this error, when the user/application did not have access to the subscription. Please double check if you did Step 5: give the user/application access to the subscription

System.AggregateException

If you get this at the authTask.Wait(); statement, check the InnerException. I got the following errors:

AADSTS65005: The client application has requested access to resource ‘https://management.azure.com/’. This request has failed because the client has not specified this resource in its requiredResourceAccess list.
This error occurs if the application does not have enough permissions. I solved it by doing Step 3: add permissions to the service management api. If you have another application, then you probably need to add other/additional permissions. For the RateCard Billing API it’s enough to configure access to the Service Management API.

AADSTS70002: The request body must contain the following parameter: ‘client_secret or client_assertion’.
I got this error when I used user authentication and the application in the Azure AD was configured as web/api application. I changed the application to native (because it is a console application) and it worked (see
Step 2: add new application to active directory).
If you use application authentication (client id + client secret), this error will not occur because the authentication process does not call the reply url.

Additional information

Microsoft Azure Billing API Code Samples: https://github.com/Azure/BillingCodeSamples
Microsoft Azure Billing API Code Samples – Usage API: https://azure.microsoft.com/en-us/resources/samples/billing-dotnet-usage-api/
Azure Billing RateCard REST API Reference: https://msdn.microsoft.com/en-us/library/azure/mt219004.aspx

Categories:

5 Responses

  1. How can i do this using a Azure CSP account?

    Its giving error :
    StatusCode: 403, ReasonPhrase: ‘Forbidden’, Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
    {
    Pragma: no-cache
    x-ms-failure-cause: gateway

  2. Get OAuth token…
    Token received, read rate card data…
    An error occurred! That’s what I got:
    StatusCode: 403, ReasonPhrase: ‘Forbidden’, Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
    {
      Pragma: no-cache
      x-ms-failure-cause: gateway
      x-ms-request-id: 46f0ccf4-775d-4a8d-b2b0-967f51e6520a
      x-ms-correlation-request-id: 46f0ccf4-775d-4a8d-b2b0-967f51e6520a
      x-ms-routing-request-id: CENTRALINDIA:20170228T120136Z:46f0ccf4-775d-4a8d-b2b0-967f51e6520a
      Strict-Transport-Security: max-age=31536000; includeSubDomains
      Connection: close
      Cache-Control: no-cache
      Date: Tue, 28 Feb 2017 12:01:35 GMT
      Content-Length: 303
      Content-Type: application/json; charset=utf-8
      Expires: -1
    }
    Press key to exit

Leave a Reply

Your email address will not be published. Required fields are marked *

About
about armin

Armin Reiter
Blockchain/Web3, IT-Security & Azure
Vienna, Austria

Reiter ITS Logo

Cryptix Logo

Legal information