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:
- Blog post: Using the Azure Billing API and calculate the costs
- NuGet Package: https://www.nuget.org/packages/CodeHollow.AzureBillingApi/
- GitHub Repository: https://github.com/codehollow/AzureBillingApi
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
5 Responses
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
Hi,
If your account is an Azure CSP account, then it should work the same way as described above. According to: https://blogs.msdn.microsoft.com/pandrew/2015/08/26/getting-started-with-the-cloud-solution-provider-apis/ – you can use the same APIs to read the ratecard data (I’ve not tested it).
The 403 forbidden usually indicates an issue with the configuration of the application in the Azure active directory. Were you able to give the user/application the rights in the Azure AD? What’s the full error message that is returned by the API?
if you are the CSP, then you need to use the Partner Center SDK (https://msdn.microsoft.com/en-us/library/partnercenter/mt774619.aspx).
I was able to give user rights to the Azure active directory
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
Unfortunately, I do not have access to an CSP Azure account, so I can’t test it. If the permissions on the active directory and the permissions for the subscription are set (step 5), then it should work. I just can imagine that there are special privileges/permissions for CSP accounts. Probably the microsoft support (https://blogs.msdn.microsoft.com/mast/2013/10/14/windows-azure-support-how-it-works-and-how-to-receive-help/) or your CSP can help.
Sorry, that I can’t help you there, but please let us know if you have any news about that.