Recently I have been working quite a bit with Azure Functions and C#. Therefore it is time to post some interesting code – at least in my opinion. One problem I wanted to solve was to list all subscriptions within your tenant having tag information and if possible the solution should be easy to extend. Well there are probably tons of ways how you could do it, but are those also performing well? Let’s talk about doing it using C# and leaving PowerShell, Azure CLI & Co. on the side.
I think there are more or less three ways how you could achieve this:
- REST call against ARM API
- Using Azure .NET SDK (which accesses also the ARM API)
- Using Azure Resource Graph SDK
I don’t want to start a fight which is the best way to achieve our goal, but for me there is are few things I like to consider when choosing one over the other.
Here just few thoughts:
- Starting with plain Rest calls, well yeah not very elegant to deal with, “noisy” output and it starts to get complicated when we try to combine information from different resources e.g. show me all resources from all subscriptions.
- Using .NET SDK is usually the way to go when interacting with Azure using C# but again if you need to join or combine outputs it gets complicated – at least for me.
- Using Azure Resource Graph is the “CMDB” for your Azure resources – now and in the future. If you have not played with it I would recommend it. The main difference between using Resource Graph API and the ARM API is, that the Resource Graph service implements the Kusto query language to perform highly performant data gathering. So there is a way to offload the actual query (for whatever result we want) to the Resource Graph service and just returning a result set that exactly matches our needs.
In this post I would like to show how I solved my problem and give you some insights how to interact with Azure Resource Graph using Azure Functions.
First I create a HTTP trigger function and adding some packages…
For this demo, I will use a service principal in Azure to authenticate and assign its permission to “Reader” on the tenant management group (I know it is not best practice, so don’t do it ), so the service principal is able to read all resources below this management group.
Then I created a Visual Studio solution ResourceGraphDemo and my ResourceGraphDemo project which contains two classes one static class to return the AzureCredentials object, needed to authenticate against Azure and the ResourceGraph class which is the actual Azure Function.
My local.settings.json contains the following data…
…as we can see it has the query for Azure Resource Graph (more later in this post), the service principal id (SP_CLIENTID aka application ID), the key (SP_KEY) and the Azure AD tenant ID (TENANTID). So let’s first see the query for Azure Resource Graph…
resourcecontainers
| where type == "microsoft.resources/subscriptions"
| extend t = parse_json(tags)
| extend costcenter = t.CostCenter
| extend stage = t.Stage
| extend domain = t.Domain
| project id, name,properties,type,costcenter,stage,domain,tags
…this query displays all subscriptions where the service principal has access to and expands the tags like stage, domain and costcenter…
…nice, exactly what we want. How are gong to put this into the Azure Function, so we get an API that throws this information back?
Let’s check the Azure Function code…
…starting with the clients we need…
…next we assign the credentials from the static credential class, initialize the subscription- and resource graph client. Additionally read the Kusto query from the local.settings.json file. Next, we need to get all available subscriptions from Azure. In my case I use some Linq magic to get only the enabled subscription subscriptions and put only the subscription Id into a list…
…and here comes the magic and performance improvement. According to Microsoft documentation it is recommended to group the queries instead of for-each looping through the subscriptions and firing of the query each time. As we can see the we need to provide the subscription Id as input for the QueryRequest parameters….
…finally we send the query and return the result as HttpresponseMessage object (or whatever you need)…
…the result will look like this…
…a nice JSON object output. So far we just mised the AzureCredentials class, because it is not so spectacular. I just use the AzureCredentialsFactory class to create the credentials object from the service principal…
…that’s it.
Final thoughts:
Well, what is this all about? In this example I call first the ARM API to get a list of all subscription Ids which serve as input for my actual resource graph client query. Would it be possible to query the resource graph client as well to get a list of subscription Ids? Yeah, sure. My thoughts were, that the ARM API is perfectly made to get this information via SDK. It is probably the most current source of truth. When it comes to work with complex data queries (which is here not the case), e.g. like displaying all the resource count in each subscription in makes more sense to offload this work to the Azure Resource Graph service using Kusto queries.
I hope this helps you and for your convenience I upload the solution to my repo on GitHub.
Microsoft.Azure.Management.ResourceGraph is deprecated. Is is recommended to use Azure.ResourceManager.ResourceGraph.
Microsoft.Azure.Management.ResourceManager.Fluent is deprecated. Is is recommended to use Azure.ResourceManager.
Microsoft.Azure.Management.Subscription is deprecated. Is is recommended to use Microsoft.Azure.Management.Subscription.
For authenticating your app in Azure please read the following:
https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication/?tabs=command-line#use-defaultazurecredential-in-an-application