skip to Main Content

I have a service principal which has access to all tenants and its resources in my organization.
The client_id client_secret and tenant_id are used in a .Net Core 6 API and following function is used to get an access token of that service principal:

public string getAccessToken(string tenantID)
        {
            var _config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
            var scopes = new string[] { _config["Azure:vm-executer:scope"]! };

            var confidentialClientApplication = ConfidentialClientApplicationBuilder
             .Create(_config["Azure:vm-executer:client_id"])
             .WithTenantId(tenantID)
             .WithClientSecret(_config["Azure:vm-executer:client_secret"])
             .WithAuthority($"https://login.microsoftonline.com/{tenantID}/oauth2/v2.0/token")
             .Build();

            var result = confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync();

            return result.Result.AccessToken;
        }

I used that access token successfully to make requests to the Azure REST API to

  1. list subscriptions with https://management.azure.com/subscriptions?api-version=2020-01-01
  2. list virtual machines with https://management.azure.com/subscriptions/{subscriptionID}/providers/Microsoft.Compute/virtualMachines?api-version=2022-11-01

I did this all in postman and it works really well!

However, now I want to do from inside my .Net 6 API.

My goal is to specifically return the response postman gave me for a specific request.
So for example when I want to list the subscriptions, then it should have the same response from postman like this:
Subscription response

So far I have implemented this function using the RestClient but I’m stuck and am in need for help.

public SubscriptionResource getSubscriptionID(string accessToken)
        {
            var uri = "https://management.azure.com/subscriptions?api-version=2020-01-01";
            var client = new RestClient();
            var request = new RestRequest(uri, Method.Get);
            request.AddHeader("Authorization", $"Bearer {accessToken}");
            RestResponse response = client.Execute(request);

            return response;
        }

I have read about the Azure SDK for .net and tried to use the Azure.ResourceManager package but without success.

2

Answers


  1. Chosen as BEST ANSWER

    While the previous answer is completely right and fine, I solved my problem by using the Azure SDK for .Net. With that I am able to retrieve all information I'm getting when calling the Azure REST API using postman. Now I can use the dot notation and resource Objects to access its attributes.

    Here is an example code of how to get the subscriptionID as well as other resources like the virtual machines inside resource groups.

    public string GetSubscriptionID(string tenantID)
        {
            var _config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
            // Create a token credential using the client ID, client secret, and tenant ID
            var credential = new ClientSecretCredential(tenantID, _config["Azure:vm-executer:client_id"], _config["Azure:vm-executer:client_secret"]);
            // Create an ArmClient with the credential
            var client = new ArmClient(credential);
            return client.GetDefaultSubscription().Data.SubscriptionId;
        }
    
        public List<VirtualMachine> GetVirtualMachines(string tenantID)
        {
            var _config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
            // Create a token credential using the client ID, client secret, and tenant ID
            var credential = new ClientSecretCredential(tenantID, _config["Azure:vm-executer:client_id"], _config["Azure:vm-executer:client_secret"]);
            // Create an ArmClient with the credential
            var client = new ArmClient(credential);
    
            // Get the list of subscriptions
            ResourceGroupCollection resourceGroups = client.GetDefaultSubscription().GetResourceGroups();
            List<VirtualMachine> vmList = new List<VirtualMachine>();
    
            foreach (ResourceGroupResource resourceGroup in resourceGroups)
            {
                VirtualMachineCollection virtualMachineCollection = resourceGroup.GetVirtualMachines();
    
                foreach (VirtualMachineResource vmResource in virtualMachineCollection)
                {
                    VirtualMachine searchedVM = new VirtualMachine();
                    searchedVM.ID = vmResource.Data.VmId;
                    searchedVM.Name = vmResource.Data.Name;
                    searchedVM.Status = "tbd";
    
                    foreach (InstanceViewStatus vmStatus in vmResource.InstanceView().Value.Statuses)
                    {
                        if (vmStatus.Code.Equals("PowerState/running"))
                        {
                            searchedVM.Status = "Running";
    
                        }
                        if (vmStatus.Code.Equals("PowerState/deallocated"))
                        {
                            searchedVM.Status = "Deallocated";
    
                        }
                    }
    
                    vmList.Add(searchedVM);
                }
            }
    
            return vmList;
        }
    

  2. I tried to reproduce the same in my environment and got below results:

    I used below c# code and got access token with list of subscriptions successfully in response like this:

    using System.Net.Http.Headers;
    using Microsoft.Identity.Client;
    
    namespace AzureRestApiListSub
    {
        class Program
        {
            private static readonly HttpClient client = new HttpClient();
    
            static async Task Main(string[] args)
            {
                // Azure AD application details
                string clientId = "bb2c371a-d0f8-492c-9252-xxxxxxxxxxxx";
                string clientSecret = "xxxxxxxxxxxxxxxxxxxxxx";
                string tenantId = "2f6e32f4-8752-4f56-9154-xxxxxxxxxxxxx";
    
                // Azure REST API endpoint
                string apiVersion = "2020-01-01";
                string endpoint = $"https://management.azure.com/subscriptions?api-version={apiVersion}";
    
                {
                    // Set up the authentication context
                    var confidentialClientApplication = ConfidentialClientApplicationBuilder
                        .Create(clientId)
                        .WithClientSecret(clientSecret)
                        .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
                        .Build();
    
                    string[] scopes = new string[] { "https://management.azure.com/.default" };
    
                    // Authenticate and acquire an access token
                    var authResult = await confidentialClientApplication
                        .AcquireTokenForClient(scopes)
                        .ExecuteAsync();
    
                    string accessToken = authResult.AccessToken;
                    Console.WriteLine(accessToken);
                    Console.WriteLine();
    
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    
                    HttpResponseMessage response = await client.GetAsync("https://management.azure.com/subscriptions?api-version=2021-01-01");
                    string json = await response.Content.ReadAsStringAsync();
                    Console.Write(json);
                    Console.WriteLine();
                }
            }
        }  
    }
    

    Response:

    enter image description here

    To confirm that, I used the above access token in Postman and got same results like below:

    GET https://management.azure.com/subscriptions?api-version=2020-01-01
    

    Response:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search